Merge "Nit clean up" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index c6ce799..0080a8d 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -81,6 +81,7 @@
         "android.view.inputmethod.flags-aconfig-java",
         "android.webkit.flags-aconfig-java",
         "android.widget.flags-aconfig-java",
+        "android.xr.flags-aconfig-java",
         "art_exported_aconfig_flags_lib",
         "backstage_power_flags_lib",
         "backup_flags_lib",
@@ -791,6 +792,12 @@
     ],
 }
 
+cc_aconfig_library {
+    name: "android.permission.flags-aconfig-cc",
+    aconfig_declarations: "android.permission.flags-aconfig",
+    host_supported: true,
+}
+
 // SQLite
 aconfig_declarations {
     name: "android.database.sqlite-aconfig",
@@ -893,6 +900,20 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+// XR
+aconfig_declarations {
+    name: "android.xr.flags-aconfig",
+    package: "android.xr",
+    container: "system",
+    srcs: ["core/java/android/content/pm/xr.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.xr.flags-aconfig-java",
+    aconfig_declarations: "android.xr.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // android.app
 aconfig_declarations {
     name: "android.app.flags-aconfig",
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 03a3a0d..46cc3f0 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -498,14 +498,6 @@
 
     private long mEJGracePeriodTopAppMs = QcConstants.DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
 
-    private long mQuotaBumpAdditionalDurationMs =
-            QcConstants.DEFAULT_QUOTA_BUMP_ADDITIONAL_DURATION_MS;
-    private int mQuotaBumpAdditionalJobCount = QcConstants.DEFAULT_QUOTA_BUMP_ADDITIONAL_JOB_COUNT;
-    private int mQuotaBumpAdditionalSessionCount =
-            QcConstants.DEFAULT_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT;
-    private long mQuotaBumpWindowSizeMs = QcConstants.DEFAULT_QUOTA_BUMP_WINDOW_SIZE_MS;
-    private int mQuotaBumpLimit = QcConstants.DEFAULT_QUOTA_BUMP_LIMIT;
-
     /**
      * List of system apps with the {@link android.Manifest.permission#INSTALL_PACKAGES} permission
      * granted for each user.
@@ -1095,7 +1087,7 @@
         // essentially run until they reach the maximum limit.
         if (stats.windowSizeMs == mAllowedTimePerPeriodMs[standbyBucket]) {
             return calculateTimeUntilQuotaConsumedLocked(
-                    events, startMaxElapsed, maxExecutionTimeRemainingMs, false);
+                    events, startMaxElapsed, maxExecutionTimeRemainingMs);
         }
 
         // Need to check both max time and period time in case one is less than the other.
@@ -1104,9 +1096,9 @@
         // bucket value.
         return Math.min(
                 calculateTimeUntilQuotaConsumedLocked(
-                        events, startMaxElapsed, maxExecutionTimeRemainingMs, false),
+                        events, startMaxElapsed, maxExecutionTimeRemainingMs),
                 calculateTimeUntilQuotaConsumedLocked(
-                        events, startWindowElapsed, allowedTimeRemainingMs, true));
+                        events, startWindowElapsed, allowedTimeRemainingMs));
     }
 
     /**
@@ -1116,36 +1108,12 @@
      * @param deadSpaceMs        How much time can be allowed to count towards the quota
      */
     private long calculateTimeUntilQuotaConsumedLocked(@NonNull List<TimedEvent> sessions,
-            final long windowStartElapsed, long deadSpaceMs, boolean allowQuotaBumps) {
+            final long windowStartElapsed, long deadSpaceMs) {
         long timeUntilQuotaConsumedMs = 0;
         long start = windowStartElapsed;
-        int numQuotaBumps = 0;
-        final long quotaBumpWindowStartElapsed =
-                sElapsedRealtimeClock.millis() - mQuotaBumpWindowSizeMs;
         final int numSessions = sessions.size();
-        if (allowQuotaBumps) {
-            for (int i = numSessions - 1; i >= 0; --i) {
-                TimedEvent event = sessions.get(i);
-
-                if (event instanceof QuotaBump) {
-                    if (event.getEndTimeElapsed() >= quotaBumpWindowStartElapsed
-                            && numQuotaBumps++ < mQuotaBumpLimit) {
-                        deadSpaceMs += mQuotaBumpAdditionalDurationMs;
-                    } else {
-                        break;
-                    }
-                }
-            }
-        }
         for (int i = 0; i < numSessions; ++i) {
-            TimedEvent event = sessions.get(i);
-
-            if (event instanceof QuotaBump) {
-                continue;
-            }
-
-            TimingSession session = (TimingSession) event;
-
+            TimingSession session = (TimingSession) sessions.get(i);
             if (session.endTimeElapsed < windowStartElapsed) {
                 // Outside of window. Ignore.
                 continue;
@@ -1330,41 +1298,15 @@
         final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
         final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
         int sessionCountInWindow = 0;
-        int numQuotaBumps = 0;
-        final long quotaBumpWindowStartElapsed = nowElapsed - mQuotaBumpWindowSizeMs;
         // The minimum time between the start time and the beginning of the events that were
         // looked at --> how much time the stats will be valid for.
         long emptyTimeMs = Long.MAX_VALUE;
         // Sessions are non-overlapping and in order of occurrence, so iterating backwards will get
         // the most recent ones.
         final int loopStart = events.size() - 1;
-        // Process QuotaBumps first to ensure the limits are properly adjusted.
-        for (int i = loopStart; i >= 0; --i) {
-            TimedEvent event = events.get(i);
-
-            if (event.getEndTimeElapsed() < quotaBumpWindowStartElapsed
-                    || numQuotaBumps >= mQuotaBumpLimit) {
-                break;
-            }
-
-            if (event instanceof QuotaBump) {
-                stats.allowedTimePerPeriodMs += mQuotaBumpAdditionalDurationMs;
-                stats.jobCountLimit += mQuotaBumpAdditionalJobCount;
-                stats.sessionCountLimit += mQuotaBumpAdditionalSessionCount;
-                emptyTimeMs = Math.min(emptyTimeMs,
-                        event.getEndTimeElapsed() - quotaBumpWindowStartElapsed);
-                numQuotaBumps++;
-            }
-        }
         TimingSession lastSeenTimingSession = null;
         for (int i = loopStart; i >= 0; --i) {
-            TimedEvent event = events.get(i);
-
-            if (event instanceof QuotaBump) {
-                continue;
-            }
-
-            TimingSession session = (TimingSession) event;
+            TimingSession session = (TimingSession) events.get(i);
 
             // Window management.
             if (startWindowElapsed < session.endTimeElapsed) {
@@ -2058,28 +2000,6 @@
     }
 
     @VisibleForTesting
-    static final class QuotaBump implements TimedEvent {
-        // Event timestamp in elapsed realtime timebase.
-        public final long eventTimeElapsed;
-
-        QuotaBump(long eventElapsed) {
-            this.eventTimeElapsed = eventElapsed;
-        }
-
-        @Override
-        public long getEndTimeElapsed() {
-            return eventTimeElapsed;
-        }
-
-        @Override
-        public void dump(IndentingPrintWriter pw) {
-            pw.print("Quota bump @ ");
-            pw.print(eventTimeElapsed);
-            pw.println();
-        }
-    }
-
-    @VisibleForTesting
     static final class ShrinkableDebits {
         /** The amount of quota remaining. Can be negative if limit changes. */
         private long mDebitTally;
@@ -2528,21 +2448,6 @@
                 updateStandbyBucket(userId, packageName, bucketIndex);
             });
         }
-
-        @Override
-        public void triggerTemporaryQuotaBump(String packageName, @UserIdInt int userId) {
-            synchronized (mLock) {
-                List<TimedEvent> events = mTimingEvents.get(userId, packageName);
-                if (events == null || events.size() == 0) {
-                    // If the app hasn't run any jobs, there's no point giving it a quota bump.
-                    return;
-                }
-                events.add(new QuotaBump(sElapsedRealtimeClock.millis()));
-                invalidateAllExecutionStatsLocked(userId, packageName);
-            }
-            // Update jobs out of band.
-            mHandler.obtainMessage(MSG_CHECK_PACKAGE, userId, 0, packageName).sendToTarget();
-        }
     }
 
     @VisibleForTesting
@@ -3019,7 +2924,6 @@
         mQcConstants.mRateLimitingConstantsUpdated = false;
         mQcConstants.mExecutionPeriodConstantsUpdated = false;
         mQcConstants.mEJLimitConstantsUpdated = false;
-        mQcConstants.mQuotaBumpConstantsUpdated = false;
     }
 
     @Override
@@ -3046,7 +2950,6 @@
         private boolean mRateLimitingConstantsUpdated = false;
         private boolean mExecutionPeriodConstantsUpdated = false;
         private boolean mEJLimitConstantsUpdated = false;
-        private boolean mQuotaBumpConstantsUpdated = false;
 
         /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */
         private static final String QC_CONSTANT_PREFIX = "qc_";
@@ -3194,21 +3097,6 @@
         @VisibleForTesting
         static final String KEY_EJ_GRACE_PERIOD_TOP_APP_MS =
                 QC_CONSTANT_PREFIX + "ej_grace_period_top_app_ms";
-        @VisibleForTesting
-        static final String KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS =
-                QC_CONSTANT_PREFIX + "quota_bump_additional_duration_ms";
-        @VisibleForTesting
-        static final String KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT =
-                QC_CONSTANT_PREFIX + "quota_bump_additional_job_count";
-        @VisibleForTesting
-        static final String KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT =
-                QC_CONSTANT_PREFIX + "quota_bump_additional_session_count";
-        @VisibleForTesting
-        static final String KEY_QUOTA_BUMP_WINDOW_SIZE_MS =
-                QC_CONSTANT_PREFIX + "quota_bump_window_size_ms";
-        @VisibleForTesting
-        static final String KEY_QUOTA_BUMP_LIMIT =
-                QC_CONSTANT_PREFIX + "quota_bump_limit";
 
         private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS =
                 10 * 60 * 1000L; // 10 minutes
@@ -3281,11 +3169,6 @@
         private static final long DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS = 0;
         private static final long DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS = 3 * MINUTE_IN_MILLIS;
         private static final long DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS = 1 * MINUTE_IN_MILLIS;
-        private static final long DEFAULT_QUOTA_BUMP_ADDITIONAL_DURATION_MS = 1 * MINUTE_IN_MILLIS;
-        private static final int DEFAULT_QUOTA_BUMP_ADDITIONAL_JOB_COUNT = 2;
-        private static final int DEFAULT_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT = 1;
-        private static final long DEFAULT_QUOTA_BUMP_WINDOW_SIZE_MS = 8 * HOUR_IN_MILLIS;
-        private static final int DEFAULT_QUOTA_BUMP_LIMIT = 8;
 
         /**
          * How much time each app in the exempted bucket will have to run jobs within their standby
@@ -3587,33 +3470,6 @@
          */
         public long EJ_GRACE_PERIOD_TOP_APP_MS = DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
 
-        /**
-         * How much additional session duration to give an app for each accepted quota bump.
-         */
-        public long QUOTA_BUMP_ADDITIONAL_DURATION_MS = DEFAULT_QUOTA_BUMP_ADDITIONAL_DURATION_MS;
-
-        /**
-         * How many additional regular jobs to give an app for each accepted quota bump.
-         */
-        public int QUOTA_BUMP_ADDITIONAL_JOB_COUNT = DEFAULT_QUOTA_BUMP_ADDITIONAL_JOB_COUNT;
-
-        /**
-         * How many additional sessions to give an app for each accepted quota bump.
-         */
-        public int QUOTA_BUMP_ADDITIONAL_SESSION_COUNT =
-                DEFAULT_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT;
-
-        /**
-         * The rolling window size within which to accept and apply quota bump events.
-         */
-        public long QUOTA_BUMP_WINDOW_SIZE_MS = DEFAULT_QUOTA_BUMP_WINDOW_SIZE_MS;
-
-        /**
-         * The maximum number of quota bumps to accept and apply within the
-         * {@link #QUOTA_BUMP_WINDOW_SIZE_MS window}.
-         */
-        public int QUOTA_BUMP_LIMIT = DEFAULT_QUOTA_BUMP_LIMIT;
-
         public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                 @NonNull String key) {
             switch (key) {
@@ -3650,14 +3506,6 @@
                     updateEJLimitConstantsLocked();
                     break;
 
-                case KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS:
-                case KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT:
-                case KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT:
-                case KEY_QUOTA_BUMP_WINDOW_SIZE_MS:
-                case KEY_QUOTA_BUMP_LIMIT:
-                    updateQuotaBumpConstantsLocked();
-                    break;
-
                 case KEY_MAX_JOB_COUNT_EXEMPTED:
                     MAX_JOB_COUNT_EXEMPTED = properties.getInt(key, DEFAULT_MAX_JOB_COUNT_EXEMPTED);
                     int newExemptedMaxJobCount =
@@ -4156,65 +4004,6 @@
             }
         }
 
-        private void updateQuotaBumpConstantsLocked() {
-            if (mQuotaBumpConstantsUpdated) {
-                return;
-            }
-            mQuotaBumpConstantsUpdated = true;
-
-            // Query the values as an atomic set.
-            final DeviceConfig.Properties properties = DeviceConfig.getProperties(
-                    DeviceConfig.NAMESPACE_JOB_SCHEDULER,
-                    KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS,
-                    KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT,
-                    KEY_QUOTA_BUMP_WINDOW_SIZE_MS, KEY_QUOTA_BUMP_LIMIT);
-            QUOTA_BUMP_ADDITIONAL_DURATION_MS = properties.getLong(
-                    KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS,
-                    DEFAULT_QUOTA_BUMP_ADDITIONAL_DURATION_MS);
-            QUOTA_BUMP_ADDITIONAL_JOB_COUNT = properties.getInt(
-                    KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, DEFAULT_QUOTA_BUMP_ADDITIONAL_JOB_COUNT);
-            QUOTA_BUMP_ADDITIONAL_SESSION_COUNT = properties.getInt(
-                    KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT,
-                    DEFAULT_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT);
-            QUOTA_BUMP_WINDOW_SIZE_MS = properties.getLong(
-                    KEY_QUOTA_BUMP_WINDOW_SIZE_MS, DEFAULT_QUOTA_BUMP_WINDOW_SIZE_MS);
-            QUOTA_BUMP_LIMIT = properties.getInt(
-                    KEY_QUOTA_BUMP_LIMIT, DEFAULT_QUOTA_BUMP_LIMIT);
-
-            // The window must be in the range [1 hour, 24 hours].
-            long newWindowSizeMs = Math.max(HOUR_IN_MILLIS,
-                    Math.min(MAX_PERIOD_MS, QUOTA_BUMP_WINDOW_SIZE_MS));
-            if (mQuotaBumpWindowSizeMs != newWindowSizeMs) {
-                mQuotaBumpWindowSizeMs = newWindowSizeMs;
-                mShouldReevaluateConstraints = true;
-            }
-            // The limit must be nonnegative.
-            int newLimit = Math.max(0, QUOTA_BUMP_LIMIT);
-            if (mQuotaBumpLimit != newLimit) {
-                mQuotaBumpLimit = newLimit;
-                mShouldReevaluateConstraints = true;
-            }
-            // The job count must be nonnegative.
-            int newJobAddition = Math.max(0, QUOTA_BUMP_ADDITIONAL_JOB_COUNT);
-            if (mQuotaBumpAdditionalJobCount != newJobAddition) {
-                mQuotaBumpAdditionalJobCount = newJobAddition;
-                mShouldReevaluateConstraints = true;
-            }
-            // The session count must be nonnegative.
-            int newSessionAddition = Math.max(0, QUOTA_BUMP_ADDITIONAL_SESSION_COUNT);
-            if (mQuotaBumpAdditionalSessionCount != newSessionAddition) {
-                mQuotaBumpAdditionalSessionCount = newSessionAddition;
-                mShouldReevaluateConstraints = true;
-            }
-            // The additional duration must be in the range [0, 10 minutes].
-            long newAdditionalDuration = Math.max(0,
-                    Math.min(10 * MINUTE_IN_MILLIS, QUOTA_BUMP_ADDITIONAL_DURATION_MS));
-            if (mQuotaBumpAdditionalDurationMs != newAdditionalDuration) {
-                mQuotaBumpAdditionalDurationMs = newAdditionalDuration;
-                mShouldReevaluateConstraints = true;
-            }
-        }
-
         private void dump(IndentingPrintWriter pw) {
             pw.println();
             pw.println("QuotaController:");
@@ -4277,15 +4066,6 @@
                     EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS).println();
             pw.print(KEY_EJ_GRACE_PERIOD_TOP_APP_MS, EJ_GRACE_PERIOD_TOP_APP_MS).println();
 
-            pw.print(KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS,
-                    QUOTA_BUMP_ADDITIONAL_DURATION_MS).println();
-            pw.print(KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT,
-                    QUOTA_BUMP_ADDITIONAL_JOB_COUNT).println();
-            pw.print(KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT,
-                    QUOTA_BUMP_ADDITIONAL_SESSION_COUNT).println();
-            pw.print(KEY_QUOTA_BUMP_WINDOW_SIZE_MS, QUOTA_BUMP_WINDOW_SIZE_MS).println();
-            pw.print(KEY_QUOTA_BUMP_LIMIT, QUOTA_BUMP_LIMIT).println();
-
             pw.decreaseIndent();
         }
 
@@ -4503,31 +4283,6 @@
         return mQcConstants;
     }
 
-    @VisibleForTesting
-    long getQuotaBumpAdditionDurationMs() {
-        return mQuotaBumpAdditionalDurationMs;
-    }
-
-    @VisibleForTesting
-    int getQuotaBumpAdditionJobCount() {
-        return mQuotaBumpAdditionalJobCount;
-    }
-
-    @VisibleForTesting
-    int getQuotaBumpAdditionSessionCount() {
-        return mQuotaBumpAdditionalSessionCount;
-    }
-
-    @VisibleForTesting
-    int getQuotaBumpLimit() {
-        return mQuotaBumpLimit;
-    }
-
-    @VisibleForTesting
-    long getQuotaBumpWindowSizeMs() {
-        return mQuotaBumpWindowSizeMs;
-    }
-
     //////////////////////////// DATA DUMP //////////////////////////////
 
     @NeverCompile // Avoid size overhead of debugging code.
diff --git a/cmds/bootanimation/OWNERS b/cmds/bootanimation/OWNERS
index b6fb007..2eda44d 100644
--- a/cmds/bootanimation/OWNERS
+++ b/cmds/bootanimation/OWNERS
@@ -1,3 +1,4 @@
 dupin@google.com
 shanh@google.com
 jreck@google.com
+rahulbanerjee@google.com
\ No newline at end of file
diff --git a/core/api/current.txt b/core/api/current.txt
index ebc534f6..f59b575 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -32782,6 +32782,8 @@
   public class Build {
     ctor public Build();
     method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
+    method @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static int getMajorSdkVersion(int);
+    method @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static int getMinorSdkVersion(int);
     method public static String getRadioVersion();
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static String getSerial();
     field public static final String BOARD;
@@ -32878,6 +32880,41 @@
   }
 
   @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static class Build.VERSION_CODES_FULL {
+    field public static final int BASE = 100000; // 0x186a0
+    field public static final int BASE_1_1 = 200000; // 0x30d40
+    field public static final int CUPCAKE = 300000; // 0x493e0
+    field public static final int DONUT = 400000; // 0x61a80
+    field public static final int ECLAIR = 500000; // 0x7a120
+    field public static final int ECLAIR_0_1 = 600000; // 0x927c0
+    field public static final int ECLAIR_MR1 = 700000; // 0xaae60
+    field public static final int FROYO = 800000; // 0xc3500
+    field public static final int GINGERBREAD = 900000; // 0xdbba0
+    field public static final int GINGERBREAD_MR1 = 1000000; // 0xf4240
+    field public static final int HONEYCOMB = 1100000; // 0x10c8e0
+    field public static final int HONEYCOMB_MR1 = 1200000; // 0x124f80
+    field public static final int HONEYCOMB_MR2 = 1300000; // 0x13d620
+    field public static final int ICE_CREAM_SANDWICH = 1400000; // 0x155cc0
+    field public static final int ICE_CREAM_SANDWICH_MR1 = 1500000; // 0x16e360
+    field public static final int JELLY_BEAN = 1600000; // 0x186a00
+    field public static final int JELLY_BEAN_MR1 = 1700000; // 0x19f0a0
+    field public static final int JELLY_BEAN_MR2 = 1800000; // 0x1b7740
+    field public static final int KITKAT = 1900000; // 0x1cfde0
+    field public static final int KITKAT_WATCH = 2000000; // 0x1e8480
+    field public static final int LOLLIPOP = 2100000; // 0x200b20
+    field public static final int LOLLIPOP_MR1 = 2200000; // 0x2191c0
+    field public static final int M = 2300000; // 0x231860
+    field public static final int N = 2400000; // 0x249f00
+    field public static final int N_MR1 = 2500000; // 0x2625a0
+    field public static final int O = 2600000; // 0x27ac40
+    field public static final int O_MR1 = 2700000; // 0x2932e0
+    field public static final int P = 2800000; // 0x2ab980
+    field public static final int Q = 2900000; // 0x2c4020
+    field public static final int R = 3000000; // 0x2dc6c0
+    field public static final int S = 3100000; // 0x2f4d60
+    field public static final int S_V2 = 3200000; // 0x30d400
+    field public static final int TIRAMISU = 3300000; // 0x325aa0
+    field public static final int UPSIDE_DOWN_CAKE = 3400000; // 0x33e140
+    field public static final int VANILLA_ICE_CREAM = 3500000; // 0x3567e0
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -33931,12 +33968,9 @@
   public class RemoteCallbackList<E extends android.os.IInterface> {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
-    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public void broadcast(@NonNull java.util.function.Consumer<E>);
     method public void finishBroadcast();
     method public Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
-    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getFrozenCalleePolicy();
-    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getMaxQueueSize();
     method public Object getRegisteredCallbackCookie(int);
     method public int getRegisteredCallbackCount();
     method public E getRegisteredCallbackItem(int);
@@ -33946,16 +33980,6 @@
     method public boolean register(E);
     method public boolean register(E, Object);
     method public boolean unregister(E);
-    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_DROP = 3; // 0x3
-    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1; // 0x1
-    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2; // 0x2
-    field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_UNSET = 0; // 0x0
-  }
-
-  @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final class RemoteCallbackList.Builder<E extends android.os.IInterface> {
-    ctor public RemoteCallbackList.Builder(int);
-    method @NonNull public android.os.RemoteCallbackList<E> build();
-    method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int);
   }
 
   public class RemoteException extends android.util.AndroidException {
@@ -43849,8 +43873,8 @@
     field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array";
     field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array";
     field public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
-    field @FlaggedApi("com.android.internal.telephony.flags.show_call_id_and_call_waiting_in_additional_settings_menu") public static final String KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL = "additional_settings_caller_id_visibility_bool";
-    field @FlaggedApi("com.android.internal.telephony.flags.show_call_id_and_call_waiting_in_additional_settings_menu") public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL = "additional_settings_call_waiting_visibility_bool";
+    field public static final String KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL = "additional_settings_caller_id_visibility_bool";
+    field public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL = "additional_settings_call_waiting_visibility_bool";
     field public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
     field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
     field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
@@ -43933,7 +43957,7 @@
     field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
     field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
-    field @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") public static final String KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY = "cellular_service_capabilities_int_array";
+    field public static final String KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY = "cellular_service_capabilities_int_array";
     field public static final String KEY_CELLULAR_USAGE_SETTING_INT = "cellular_usage_setting_int";
     field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool";
     field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
@@ -45909,6 +45933,7 @@
     method public byte[] getPdu();
     method public int getProtocolIdentifier();
     method public String getPseudoSubject();
+    method @FlaggedApi("com.android.internal.telephony.flags.support_sms_over_ims_apis") @Nullable public String getRecipientAddress();
     method public String getServiceCenterAddress();
     method public int getStatus();
     method public int getStatusOnIcc();
@@ -45970,7 +45995,7 @@
     method @Nullable public String getMncString();
     method @Deprecated public String getNumber();
     method public int getPortIndex();
-    method @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") @NonNull public java.util.Set<java.lang.Integer> getServiceCapabilities();
+    method @NonNull public java.util.Set<java.lang.Integer> getServiceCapabilities();
     method public int getSimSlotIndex();
     method public int getSubscriptionId();
     method public int getSubscriptionType();
@@ -46053,9 +46078,9 @@
     field public static final int PHONE_NUMBER_SOURCE_CARRIER = 2; // 0x2
     field public static final int PHONE_NUMBER_SOURCE_IMS = 3; // 0x3
     field public static final int PHONE_NUMBER_SOURCE_UICC = 1; // 0x1
-    field @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") public static final int SERVICE_CAPABILITY_DATA = 3; // 0x3
-    field @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") public static final int SERVICE_CAPABILITY_SMS = 2; // 0x2
-    field @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") public static final int SERVICE_CAPABILITY_VOICE = 1; // 0x1
+    field public static final int SERVICE_CAPABILITY_DATA = 3; // 0x3
+    field public static final int SERVICE_CAPABILITY_SMS = 2; // 0x2
+    field public static final int SERVICE_CAPABILITY_VOICE = 1; // 0x1
     field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
     field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
     field public static final int USAGE_SETTING_DATA_CENTRIC = 2; // 0x2
@@ -46304,8 +46329,8 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataEnabled();
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataEnabledForReason(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataRoamingEnabled();
-    method @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") public boolean isDeviceSmsCapable();
-    method @FlaggedApi("com.android.internal.telephony.flags.data_only_cellular_service") public boolean isDeviceVoiceCapable();
+    method public boolean isDeviceSmsCapable();
+    method public boolean isDeviceVoiceCapable();
     method public boolean isEmergencyNumber(@NonNull String);
     method public boolean isHearingAidCompatibilitySupported();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed();
@@ -46364,7 +46389,7 @@
     field public static final String ACTION_MULTI_SIM_CONFIG_CHANGED = "android.telephony.action.MULTI_SIM_CONFIG_CHANGED";
     field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED";
     field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
-    field @FlaggedApi("com.android.internal.telephony.flags.reset_mobile_network_settings") public static final String ACTION_RESET_MOBILE_NETWORK_SETTINGS = "android.telephony.action.RESET_MOBILE_NETWORK_SETTINGS";
+    field public static final String ACTION_RESET_MOBILE_NETWORK_SETTINGS = "android.telephony.action.RESET_MOBILE_NETWORK_SETTINGS";
     field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
     field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
@@ -50944,6 +50969,7 @@
     method public android.view.Display.Mode[] getSupportedModes();
     method @Deprecated public float[] getSupportedRefreshRates();
     method @Deprecated public int getWidth();
+    method @FlaggedApi("com.android.server.display.feature.flags.enable_has_arr_support") public boolean hasArrSupport();
     method public boolean isHdr();
     method public boolean isHdrSdrRatioAvailable();
     method public boolean isMinimalPostProcessingSupported();
@@ -56597,7 +56623,7 @@
     method public java.util.Map<android.view.inputmethod.InputMethodInfo,java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
     method @Deprecated public void hideSoftInputFromInputMethod(android.os.IBinder, int);
     method public boolean hideSoftInputFromWindow(android.os.IBinder, int);
-    method public boolean hideSoftInputFromWindow(android.os.IBinder, int, android.os.ResultReceiver);
+    method @Deprecated public boolean hideSoftInputFromWindow(android.os.IBinder, int, android.os.ResultReceiver);
     method @Deprecated public void hideStatusIcon(android.os.IBinder);
     method public void invalidateInput(@NonNull android.view.View);
     method public boolean isAcceptingText();
@@ -56621,7 +56647,7 @@
     method public void showInputMethodAndSubtypeEnabler(@Nullable String);
     method public void showInputMethodPicker();
     method public boolean showSoftInput(android.view.View, int);
-    method public boolean showSoftInput(android.view.View, int, android.os.ResultReceiver);
+    method @Deprecated public boolean showSoftInput(android.view.View, int, android.os.ResultReceiver);
     method @Deprecated public void showSoftInputFromInputMethod(android.os.IBinder, int);
     method @Deprecated public void showStatusIcon(android.os.IBinder, String, @DrawableRes int);
     method @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public void startConnectionlessStylusHandwriting(@NonNull android.view.View, @Nullable android.view.inputmethod.CursorAnchorInfo, @NonNull java.util.concurrent.Executor, @NonNull android.view.inputmethod.ConnectionlessHandwritingCallback);
@@ -61684,6 +61710,8 @@
 
   public final class BackEvent {
     ctor public BackEvent(float, float, float, int);
+    ctor @FlaggedApi("com.android.window.flags.predictive_back_timestamp_api") public BackEvent(float, float, float, int, long);
+    method @FlaggedApi("com.android.window.flags.predictive_back_timestamp_api") public long getFrameTime();
     method @FloatRange(from=0, to=1) public float getProgress();
     method public int getSwipeEdge();
     method public float getTouchX();
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 3c7c0d6..a3cab29 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -82,12 +82,12 @@
 package android.graphics {
 
   @Deprecated public class AvoidXfermode extends android.graphics.Xfermode {
-    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
+    ctor @Deprecated public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
   }
 
-  public enum AvoidXfermode.Mode {
-    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
-    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
+  @Deprecated public enum AvoidXfermode.Mode {
+    enum_constant @Deprecated public static final android.graphics.AvoidXfermode.Mode AVOID;
+    enum_constant @Deprecated public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
   public class Canvas {
@@ -102,9 +102,9 @@
   }
 
   @Deprecated public class LayerRasterizer extends android.graphics.Rasterizer {
-    ctor public LayerRasterizer();
-    method public void addLayer(android.graphics.Paint, float, float);
-    method public void addLayer(android.graphics.Paint);
+    ctor @Deprecated public LayerRasterizer();
+    method @Deprecated public void addLayer(android.graphics.Paint, float, float);
+    method @Deprecated public void addLayer(android.graphics.Paint);
   }
 
   public class Paint {
@@ -118,7 +118,7 @@
   }
 
   @Deprecated public class PixelXorXfermode extends android.graphics.Xfermode {
-    ctor public PixelXorXfermode(int);
+    ctor @Deprecated public PixelXorXfermode(int);
   }
 
   public class Rasterizer {
@@ -170,14 +170,14 @@
 package android.net {
 
   @Deprecated public class NetworkBadging {
-    method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
-    field public static final int BADGING_4K = 30; // 0x1e
-    field public static final int BADGING_HD = 20; // 0x14
-    field public static final int BADGING_NONE = 0; // 0x0
-    field public static final int BADGING_SD = 10; // 0xa
+    method @Deprecated @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
+    field @Deprecated public static final int BADGING_4K = 30; // 0x1e
+    field @Deprecated public static final int BADGING_HD = 20; // 0x14
+    field @Deprecated public static final int BADGING_NONE = 0; // 0x0
+    field @Deprecated public static final int BADGING_SD = 10; // 0xa
   }
 
-  @IntDef({0x0, 0xa, 0x14, 0x1e}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NetworkBadging.Badging {
+  @Deprecated @IntDef({0x0, 0xa, 0x14, 0x1e}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NetworkBadging.Badging {
   }
 
   public final class Proxy {
@@ -304,14 +304,14 @@
 
   @Deprecated public static final class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
     field @Deprecated public static final String CONTENT_DIRECTORY = "stream_items";
-    field public static final String _COUNT = "_count";
-    field public static final String _ID = "_id";
+    field @Deprecated public static final String _COUNT = "_count";
+    field @Deprecated public static final String _ID = "_id";
   }
 
   @Deprecated public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
     field @Deprecated public static final String PHOTO = "photo";
-    field public static final String _COUNT = "_count";
-    field public static final String _ID = "_id";
+    field @Deprecated public static final String _COUNT = "_count";
+    field @Deprecated public static final String _ID = "_id";
   }
 
   @Deprecated protected static interface ContactsContract.StreamItemPhotosColumns {
@@ -332,16 +332,16 @@
     field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
     field @Deprecated public static final android.net.Uri CONTENT_URI;
     field @Deprecated public static final String MAX_ITEMS = "max_items";
-    field public static final String _COUNT = "_count";
-    field public static final String _ID = "_id";
+    field @Deprecated public static final String _COUNT = "_count";
+    field @Deprecated public static final String _ID = "_id";
   }
 
   @Deprecated public static final class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
     field @Deprecated public static final String CONTENT_DIRECTORY = "photo";
     field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo";
     field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
-    field public static final String _COUNT = "_count";
-    field public static final String _ID = "_id";
+    field @Deprecated public static final String _COUNT = "_count";
+    field @Deprecated public static final String _ID = "_id";
   }
 
   @Deprecated protected static interface ContactsContract.StreamItemsColumns {
@@ -447,14 +447,14 @@
 package android.util {
 
   @Deprecated public class FloatMath {
-    method public static float ceil(float);
-    method public static float cos(float);
-    method public static float exp(float);
-    method public static float floor(float);
-    method public static float hypot(float, float);
-    method public static float pow(float, float);
-    method public static float sin(float);
-    method public static float sqrt(float);
+    method @Deprecated public static float ceil(float);
+    method @Deprecated public static float cos(float);
+    method @Deprecated public static float exp(float);
+    method @Deprecated public static float floor(float);
+    method @Deprecated public static float hypot(float, float);
+    method @Deprecated public static float pow(float, float);
+    method @Deprecated public static float sin(float);
+    method @Deprecated public static float sqrt(float);
   }
 
 }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 49b711b..fa4fc43 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7319,6 +7319,7 @@
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_CLIENT_VOLUME = 16; // 0x10
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_MASTER = 1; // 0x1
+    field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_PORT_VOLUME = 64; // 0x40
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_MUTED = 4; // 0x4
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_VOLUME = 2; // 0x2
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_VOLUME_SHAPER = 32; // 0x20
@@ -13104,7 +13105,7 @@
     method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
     method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
     method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
-    method @Deprecated public void onAllowedAdjustmentsChanged();
+    method public void onAllowedAdjustmentsChanged();
     method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
     method public void onNotificationClicked(@NonNull String);
     method public void onNotificationDirectReplied(@NonNull String);
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index bbfa0ec..78b9994 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -7,8 +7,8 @@
   }
 
   @Deprecated public abstract static class AppOpsManager.AppOpsCollector extends android.app.AppOpsManager.OnOpNotedCallback {
-    ctor public AppOpsManager.AppOpsCollector();
-    method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
+    ctor @Deprecated public AppOpsManager.AppOpsCollector();
+    method @Deprecated @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
   }
 
   public class Notification implements android.os.Parcelable {
@@ -207,7 +207,7 @@
 
   @Deprecated public static interface TranslationService.OnTranslationResultCallback {
     method @Deprecated public void onError();
-    method public void onTranslationSuccess(@NonNull android.view.translation.TranslationResponse);
+    method @Deprecated public void onTranslationSuccess(@NonNull android.view.translation.TranslationResponse);
   }
 
 }
@@ -261,64 +261,64 @@
   }
 
   @Deprecated public final class SipDelegateImsConfiguration implements android.os.Parcelable {
-    method public boolean containsKey(@NonNull String);
-    method @NonNull public android.os.PersistableBundle copyBundle();
-    method public int describeContents();
-    method public boolean getBoolean(@NonNull String, boolean);
-    method public int getInt(@NonNull String, int);
-    method @Nullable public String getString(@NonNull String);
-    method public long getVersion();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
-    field public static final String IPTYPE_IPV4 = "IPV4";
-    field public static final String IPTYPE_IPV6 = "IPV6";
-    field public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
-    field public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
-    field public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
-    field public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
-    field public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
-    field public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
-    field public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
-    field public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
-    field public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
-    field public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
-    field public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
-    field public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
-    field public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
-    field public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
-    field public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
-    field public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
-    field public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
-    field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
-    field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
-    field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
-    field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
-    field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
-    field public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
-    field public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
-    field public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
-    field public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
-    field public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
-    field public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
-    field public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
-    field public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
-    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
-    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
-    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
-    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
-    field public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
-    field public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
-    field public static final String SIP_TRANSPORT_TCP = "TCP";
-    field public static final String SIP_TRANSPORT_UDP = "UDP";
+    method @Deprecated public boolean containsKey(@NonNull String);
+    method @Deprecated @NonNull public android.os.PersistableBundle copyBundle();
+    method @Deprecated public int describeContents();
+    method @Deprecated public boolean getBoolean(@NonNull String, boolean);
+    method @Deprecated public int getInt(@NonNull String, int);
+    method @Deprecated @Nullable public String getString(@NonNull String);
+    method @Deprecated public long getVersion();
+    method @Deprecated public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
+    field @Deprecated public static final String IPTYPE_IPV4 = "IPV4";
+    field @Deprecated public static final String IPTYPE_IPV6 = "IPV6";
+    field @Deprecated public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
+    field @Deprecated public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
+    field @Deprecated public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
+    field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
+    field @Deprecated public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
+    field @Deprecated public static final String SIP_TRANSPORT_TCP = "TCP";
+    field @Deprecated public static final String SIP_TRANSPORT_UDP = "UDP";
   }
 
-  public static final class SipDelegateImsConfiguration.Builder {
-    ctor public SipDelegateImsConfiguration.Builder(int);
-    ctor public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
-    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
-    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
-    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
-    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
+  @Deprecated public static final class SipDelegateImsConfiguration.Builder {
+    ctor @Deprecated public SipDelegateImsConfiguration.Builder(int);
+    ctor @Deprecated public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+    method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
+    method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
+    method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
+    method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5e4485c..1ff8c51 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -393,7 +393,9 @@
 
   public class NotificationManager {
     method @FlaggedApi("android.app.modes_api") @NonNull public String addAutomaticZenRule(@NonNull android.app.AutomaticZenRule, boolean);
+    method @FlaggedApi("android.service.notification.notification_classification") public void allowAssistantAdjustment(@NonNull String);
     method public void cleanUpCallersAfter(long);
+    method @FlaggedApi("android.service.notification.notification_classification") public void disallowAssistantAdjustment(@NonNull String);
     method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy getDefaultZenPolicy();
     method public android.content.ComponentName getEffectsSuppressor();
     method @FlaggedApi("android.service.notification.notification_classification") @NonNull public java.util.Set<java.lang.String> getUnsupportedAdjustmentTypes();
@@ -1099,6 +1101,7 @@
     field public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT = 265452344L; // 0xfd27b38L
     field public static final long OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION = 255940284L; // 0xf4156bcL
     field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
+    field public static final long UNIVERSAL_RESIZABLE_BY_DEFAULT = 357141415L; // 0x15498ba7L
   }
 
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 1265de1..65cd984 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -214,6 +214,9 @@
 
 aidl_interface {
     name: "android.os.hintmanager_aidl",
+    defaults: [
+        "android.hardware.power-aidl",
+    ],
     srcs: [
         "android/os/IHintManager.aidl",
         "android/os/IHintSession.aidl",
@@ -231,9 +234,6 @@
             enabled: true,
         },
     },
-    imports: [
-        "android.hardware.power-V5",
-    ],
 }
 
 aidl_library {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0c02ba4..99625ac 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3841,6 +3841,18 @@
         return activityRecord != null ? activityRecord.activity : null;
     }
 
+    /**
+     * Returns the most recent created activity that's still running.
+     */
+    @Nullable
+    public Activity getLastCreatedActivity() {
+        if (mActivities.isEmpty()) {
+            return null;
+        }
+
+        return mActivities.valueAt(mActivities.size() - 1).activity;
+    }
+
     @Override
     public ActivityClientRecord getActivityClient(IBinder token) {
         return mActivities.get(token);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 3b2aab4..a7597b4 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -84,6 +84,8 @@
     boolean isImportanceLocked(String pkg, int uid);
 
     List<String> getAllowedAssistantAdjustments(String pkg);
+    void allowAssistantAdjustment(String adjustmentType);
+    void disallowAssistantAdjustment(String adjustmentType);
 
     boolean shouldHideSilentStatusIcons(String callingPkg);
     void setHideSilentStatusIcons(boolean hide);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8b33417..4ef5b51 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -11296,7 +11296,11 @@
          * @see Segment
          */
         public @NonNull ProgressStyle setProgressSegments(@NonNull List<Segment> progressSegments) {
-            mProgressSegments = new ArrayList<>(progressSegments.size());
+            if (mProgressSegments == null) {
+                mProgressSegments = new ArrayList<>();
+            }
+            mProgressSegments.clear();
+            mProgressSegments.addAll(progressSegments);
             return this;
         }
 
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 41abd68..06bf67c 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1790,6 +1790,34 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @TestApi
+    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+    public void allowAssistantAdjustment(@NonNull String capability) {
+        INotificationManager service = getService();
+        try {
+            service.allowAssistantAdjustment(capability);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+    public void disallowAssistantAdjustment(@NonNull String capability) {
+        INotificationManager service = getService();
+        try {
+            service.disallowAssistantAdjustment(capability);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     @TestApi
     public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String pkg) {
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
index 08ecced..06d95f5 100644
--- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
+++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
@@ -137,8 +137,10 @@
                                                 .TOKENIZER_TYPE_VERBATIM)
                                 .build())
                 .addProperty(
-                        new AppSearchSchema.BooleanPropertyConfig.Builder(PROPERTY_ENABLED)
+                        new AppSearchSchema.LongPropertyConfig.Builder(PROPERTY_ENABLED)
                                 .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                                .setIndexingType(
+                                        AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_RANGE)
                                 .build())
                 .addProperty(
                         new AppSearchSchema.StringPropertyConfig.Builder(
@@ -212,19 +214,14 @@
         }
 
         /**
-         * Sets an indicator specifying if the function is enabled or not. This would override the
-         * default enabled state in the static metadata ({@link
-         * AppFunctionStaticMetadataHelper#STATIC_PROPERTY_ENABLED_BY_DEFAULT}). Sets this to null
-         * to clear the override.
-         * TODO(369683073) Replace the tristate Boolean with IntDef EnabledState.
+         * Sets an indicator specifying the function enabled state.
          */
         @NonNull
         public Builder setEnabled(@EnabledState int enabledState) {
             if (enabledState != APP_FUNCTION_STATE_DEFAULT
                     && enabledState != APP_FUNCTION_STATE_ENABLED
                     && enabledState != APP_FUNCTION_STATE_DISABLED) {
-                throw new IllegalArgumentException(
-                        "Value of EnabledState is unsupported.");
+                throw new IllegalArgumentException("Value of EnabledState is unsupported.");
             }
             setPropertyLong(PROPERTY_ENABLED, enabledState);
             return this;
diff --git a/core/java/android/app/contextualsearch/ContextualSearchManager.java b/core/java/android/app/contextualsearch/ContextualSearchManager.java
index cfbe741..3438cc8 100644
--- a/core/java/android/app/contextualsearch/ContextualSearchManager.java
+++ b/core/java/android/app/contextualsearch/ContextualSearchManager.java
@@ -102,6 +102,7 @@
      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
      */
     public static final String EXTRA_TOKEN = "android.app.contextualsearch.extra.TOKEN";
+
     /**
      * Intent action for contextual search invocation. The app providing the contextual search
      * experience must add this intent filter action to the activity it wants to be launched.
@@ -111,6 +112,14 @@
     public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH =
             "android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH";
 
+    /**
+     * System feature declaring that the device supports Contextual Search.
+     *
+     * @hide
+     */
+    public static final String FEATURE_CONTEXTUAL_SEARCH =
+            "com.google.android.feature.CONTEXTUAL_SEARCH";
+
     /** Entrypoint to be used when a user long presses on the nav handle. */
     public static final int ENTRYPOINT_LONG_PRESS_NAV_HANDLE = 1;
     /** Entrypoint to be used when a user long presses on the home button. */
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 8014537..37fa9a26 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -6,6 +6,14 @@
 # flag relates to.
 
 flag {
+  name: "notifications_redesign_app_icons"
+  namespace: "systemui"
+  description: "Notifications Redesign: Use app icons in notification rows (not to be confused with"
+    " notifications_use_app_icons, notifications_use_app_icon_in_row which are just experiments)."
+  bug: "371174789"
+}
+
+flag {
   name: "modes_api"
   is_exported: true
   namespace: "systemui"
@@ -48,6 +56,16 @@
 }
 
 flag {
+  name: "modes_hsum"
+  namespace: "systemui"
+  description: "Fixes for modes (and DND/Zen in general) with HSUM or secondary users"
+  bug: "366203070"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "api_tvextender"
   is_exported: true
   namespace: "systemui"
@@ -262,3 +280,10 @@
   description: "[RONs] Guards new promotion logic and UI, including AOD notification and Colorization"
   bug: "367705002"
 }
+
+flag {
+  name: "backup_restore_logging"
+  namespace: "systemui"
+  description: "Adds logging for notification/modes backup and restore events"
+  bug: "289524803"
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 481e6b5..ce52825 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -21,10 +21,12 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.Activity;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.Overridable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -1204,6 +1206,18 @@
     public @interface SizeChangesSupportMode {}
 
     /**
+     * This change id makes the restriction of fixed orientation, aspect ratio, and resizability
+     * of the app to be ignored, which means making the app fill the given available area.
+     * @hide
+     */
+    @ChangeId
+    @Overridable
+    @TestApi
+    @SuppressLint("UnflaggedApi") // @TestApi without associated public API.
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public static final long UNIVERSAL_RESIZABLE_BY_DEFAULT = 357141415L; // buganizer id
+
+    /**
      * This change id enables compat policy that ignores app requested orientation in
      * response to an app calling {@link android.app.Activity#setRequestedOrientation}. See
      * com.android.server.wm.LetterboxUiController#shouldIgnoreRequestedOrientation for
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index c7d7dc1..52d7333 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -326,3 +326,11 @@
     bug: "360129103"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "include_feature_flags_in_package_cacher"
+    namespace: "package_manager_service"
+    description: "Include feature flag status when determining hits or misses in PackageCacher."
+    bug: "364771256"
+    is_fixed_read_only: true
+}
diff --git a/core/java/android/content/pm/xr.aconfig b/core/java/android/content/pm/xr.aconfig
new file mode 100644
index 0000000..61835c1
--- /dev/null
+++ b/core/java/android/content/pm/xr.aconfig
@@ -0,0 +1,9 @@
+package: "android.xr"
+container: "system"
+
+flag {
+    namespace: "xr"
+    name: "xr_manifest_entries"
+    description: "Adds manifest entries used by Android XR"
+    bug: "364416355"
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 99eeca9..f03a4a9 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -142,3 +142,10 @@
   description: "Controls whether the connected mice's primary buttons, left and right, can be swapped."
   bug: "352598211"
 }
+
+flag {
+  name: "keyboard_a11y_shortcut_control"
+  namespace: "input"
+  description: "Adds shortcuts to toggle and control a11y features"
+  bug: "373458181"
+}
diff --git a/core/java/android/hardware/radio/RadioAlert.aidl b/core/java/android/hardware/radio/RadioAlert.aidl
new file mode 100644
index 0000000..17f4fc7
--- /dev/null
+++ b/core/java/android/hardware/radio/RadioAlert.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio;
+
+/** @hide */
+parcelable RadioAlert;
\ No newline at end of file
diff --git a/core/java/android/hardware/radio/RadioAlert.java b/core/java/android/hardware/radio/RadioAlert.java
new file mode 100644
index 0000000..b55dcd8
--- /dev/null
+++ b/core/java/android/hardware/radio/RadioAlert.java
@@ -0,0 +1,505 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio;
+
+import android.annotation.FlaggedApi;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Emergency Alert Message
+ *
+ * <p>Alert message can be sent from a radio station of technologies such as HD radio to
+ * the radio users for some emergency events (see ITU-T X.1303 bis for more info).
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM)
+public final class RadioAlert implements Parcelable {
+
+    public static final class Geocode implements Parcelable {
+
+        private final String mValueName;
+        private final String mValue;
+
+        /**
+         * Constructor of geocode.
+         *
+         * @param valueName Name of geocode value
+         * @param value Value of geocode
+         * @hide
+         */
+        public Geocode(@NonNull String valueName, @NonNull String value) {
+            mValueName = Objects.requireNonNull(valueName, "Geocode value name can not be null");
+            mValue = Objects.requireNonNull(value, "Geocode value can not be null");
+        }
+
+        private Geocode(Parcel in) {
+            mValueName = in.readString8();
+            mValue = in.readString8();
+        }
+
+        public static final @NonNull Creator<Geocode> CREATOR = new Creator<Geocode>() {
+            @Override
+            public Geocode createFromParcel(Parcel in) {
+                return new Geocode(in);
+            }
+
+            @Override
+            public Geocode[] newArray(int size) {
+                return new Geocode[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeString8(mValueName);
+            dest.writeString8(mValue);
+        }
+
+        @NonNull
+        @Override
+        public String toString() {
+            return "Gecode [valueName=" + mValueName + ", value=" + mValue + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mValueName, mValue);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof Geocode other)) {
+                return false;
+            }
+
+            return Objects.equals(mValueName, other.mValueName)
+                    && Objects.equals(mValue, other.mValue);
+        }
+    }
+
+    public static final class Coordinate implements Parcelable {
+        private final double mLatitude;
+        private final double mLongitude;
+
+        /**
+         * Constructor of coordinate.
+         *
+         * @param latitude Latitude of the coordinate
+         * @param longitude Longitude of the coordinate
+         * @hide
+         */
+        public Coordinate(double latitude, double longitude) {
+            if (latitude < -90.0 || latitude > 90.0) {
+                throw new IllegalArgumentException("Latitude value should be between -90 and 90");
+            }
+            if (longitude < -180.0 || longitude > 180.0) {
+                throw new IllegalArgumentException(
+                        "Longitude value should be between -180 and 180");
+            }
+            mLatitude = latitude;
+            mLongitude = longitude;
+        }
+
+        private Coordinate(Parcel in) {
+            mLatitude = in.readDouble();
+            mLongitude = in.readDouble();
+        }
+
+        public static final @NonNull Creator<Coordinate> CREATOR = new Creator<Coordinate>() {
+            @Override
+            public Coordinate createFromParcel(Parcel in) {
+                return new Coordinate(in);
+            }
+
+            @Override
+            public Coordinate[] newArray(int size) {
+                return new Coordinate[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeDouble(mLatitude);
+            dest.writeDouble(mLongitude);
+        }
+
+        @NonNull
+        @Override
+        public String toString() {
+            return "Coordinate [latitude=" + mLatitude + ", longitude=" + mLongitude + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mLatitude, mLongitude);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof Coordinate other)) {
+                return false;
+            }
+            return mLatitude == other.mLatitude && mLongitude == other.mLongitude;
+        }
+    }
+
+    public static final class Polygon implements Parcelable {
+
+        private final List<Coordinate> mCoordinates;
+
+        /**
+         * Constructor of polygon.
+         *
+         * @param coordinates Coordinates the polygon is composed of
+         * @hide
+         */
+        public Polygon(@NonNull List<Coordinate> coordinates) {
+            Objects.requireNonNull(coordinates, "Coordinates can not be null");
+            if (coordinates.size() < 4) {
+                throw new IllegalArgumentException("Number of coordinates must be at least 4");
+            }
+            if (!coordinates.get(0).equals(coordinates.get(coordinates.size() - 1))) {
+                throw new IllegalArgumentException(
+                        "The last and first coordinates must be the same");
+            }
+            mCoordinates = coordinates;
+        }
+
+        private Polygon(Parcel in) {
+            mCoordinates = new ArrayList<>();
+            in.readTypedList(mCoordinates, Coordinate.CREATOR);
+        }
+
+        public static final @NonNull Creator<Polygon> CREATOR = new Creator<Polygon>() {
+            @Override
+            public Polygon createFromParcel(Parcel in) {
+                return new Polygon(in);
+            }
+
+            @Override
+            public Polygon[] newArray(int size) {
+                return new Polygon[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeTypedList(mCoordinates);
+        }
+
+        @NonNull
+        @Override
+        public String toString() {
+            return "Polygon [coordinates=" + mCoordinates + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mCoordinates);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof Polygon other)) {
+                return false;
+            }
+            return mCoordinates.equals(other.mCoordinates);
+        }
+    }
+
+    public static final class AlertArea implements Parcelable {
+
+        private final List<Polygon> mPolygons;
+        private final List<Geocode> mGeocodes;
+
+        /**
+         * Constructor of alert area.
+         *
+         * @param polygons Polygons used in alert area
+         * @param geocodes Geocodes used in alert area
+         * @hide
+         */
+        public AlertArea(@NonNull List<Polygon> polygons, @NonNull List<Geocode> geocodes) {
+            mPolygons = Objects.requireNonNull(polygons, "Polygons can not be null");
+            mGeocodes = Objects.requireNonNull(geocodes, "Geocodes can not be null");
+        }
+
+        private AlertArea(Parcel in) {
+            mPolygons = new ArrayList<>();
+            mGeocodes = new ArrayList<>();
+            in.readTypedList(mPolygons, Polygon.CREATOR);
+            in.readTypedList(mGeocodes, Geocode.CREATOR);
+        }
+
+        public static final @NonNull Creator<AlertArea> CREATOR = new Creator<AlertArea>() {
+            @Override
+            public AlertArea createFromParcel(Parcel in) {
+                return new AlertArea(in);
+            }
+
+            @Override
+            public AlertArea[] newArray(int size) {
+                return new AlertArea[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeTypedList(mPolygons);
+            dest.writeTypedList(mGeocodes);
+        }
+
+        @NonNull
+        @Override
+        public String toString() {
+            return "AlertArea [polygons=" + mPolygons + ", geocodes=" + mGeocodes + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mPolygons, mGeocodes);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof AlertArea other)) {
+                return false;
+            }
+
+            return mPolygons.equals(other.mPolygons) && mGeocodes.equals(other.mGeocodes);
+        }
+    }
+
+    public static final class AlertInfo implements Parcelable {
+
+        private final List<Integer> mCategoryList;
+        private final int mUrgency;
+        private final int mSeverity;
+        private final int mCertainty;
+        private final String mTextualMessage;
+        private final List<AlertArea> mAreaList;
+
+        /**
+         * Constructor for alert info.
+         *
+         * @param categoryList Array of categories of the subject event of the alert message
+         * @param urgency The urgency of the subject event of the alert message
+         * @param severity The severity of the subject event of the alert message
+         * @param certainty The certainty of the subject event of the alert message
+         * @param textualMessage Textual descriptions of the subject event
+         * @param areaList The array of geographic areas to which the alert info segment in which
+         *                 it appears applies
+         * @hide
+         */
+        public AlertInfo(@NonNull List<Integer> categoryList, int urgency,
+                int severity, int certainty,
+                String textualMessage, @NonNull List<AlertArea> areaList) {
+            mCategoryList = Objects.requireNonNull(categoryList, "Category list can not be null");
+            mUrgency = urgency;
+            mSeverity = severity;
+            mCertainty = certainty;
+            mTextualMessage = textualMessage;
+            mAreaList = Objects.requireNonNull(areaList, "Area list can not be null");
+        }
+
+        private AlertInfo(Parcel in) {
+            mCategoryList = in.readArrayList(Integer.class.getClassLoader(), Integer.class);
+            mUrgency = in.readInt();
+            mSeverity = in.readInt();
+            mCertainty = in.readInt();
+            mTextualMessage = in.readString8();
+            mAreaList = new ArrayList<>();
+            in.readTypedList(mAreaList, AlertArea.CREATOR);
+        }
+
+        public static final @NonNull Creator<AlertInfo> CREATOR = new Creator<AlertInfo>() {
+            @Override
+            public AlertInfo createFromParcel(Parcel in) {
+                return new AlertInfo(in);
+            }
+
+            @Override
+            public AlertInfo[] newArray(int size) {
+                return new AlertInfo[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeList(mCategoryList);
+            dest.writeInt(mUrgency);
+            dest.writeInt(mSeverity);
+            dest.writeInt(mCertainty);
+            dest.writeString8(mTextualMessage);
+            dest.writeTypedList(mAreaList);
+        }
+
+        @NonNull
+        @Override
+        public String toString() {
+            return "AlertInfo [categoryList=" + mCategoryList + ", urgency=" + mUrgency
+                    + ", severity=" + mSeverity + ", certainty=" + mCertainty
+                    + ", textualMessage=" + mTextualMessage + ", areaList=" + mAreaList + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mCategoryList, mUrgency, mSeverity, mCertainty, mTextualMessage,
+                    mAreaList);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof AlertInfo other)) {
+                return false;
+            }
+
+            return mCategoryList.equals(other.mCategoryList) && mUrgency == other.mUrgency
+                    && mSeverity == other.mSeverity && mCertainty == other.mCertainty
+                    && mTextualMessage.equals(other.mTextualMessage)
+                    && mAreaList.equals(other.mAreaList);
+        }
+    }
+
+    private final int mStatus;
+    private final int mMessageType;
+    private final List<AlertInfo> mInfoList;
+    private final int mScope;
+
+    /**
+     * Constructor of radio alert message.
+     *
+     * @param status Status of alert message
+     * @param messageType Message type of alert message
+     * @param infoList List of alert info
+     * @param scope Scope of alert message
+     * @hide
+     */
+    public RadioAlert(int status, int messageType,
+            @NonNull List<AlertInfo> infoList, int scope) {
+        mStatus = status;
+        mMessageType = messageType;
+        mInfoList = Objects.requireNonNull(infoList, "Alert info list can not be null");
+        mScope = scope;
+    }
+
+    private RadioAlert(Parcel in) {
+        mStatus = in.readInt();
+        mMessageType = in.readInt();
+        mInfoList = in.readParcelableList(new ArrayList<>(), AlertInfo.class.getClassLoader(),
+                AlertInfo.class);
+        mScope = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStatus);
+        dest.writeInt(mMessageType);
+        dest.writeParcelableList(mInfoList, /* flags= */ 0);
+        dest.writeInt(mScope);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "RadioAlert [status=" + mStatus + ", messageType=" + mMessageType
+                + ", infoList= " + mInfoList + ", scope=" + mScope + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStatus, mMessageType, mInfoList, mScope);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof RadioAlert other)) {
+            return false;
+        }
+
+        return mStatus == other.mStatus && mMessageType == other.mMessageType
+                && mInfoList.equals(other.mInfoList) && mScope == other.mScope;
+    }
+
+    public static final @NonNull Creator<RadioAlert> CREATOR = new Creator<RadioAlert>() {
+        @Override
+        public RadioAlert createFromParcel(Parcel in) {
+            return new RadioAlert(in);
+        }
+
+        @Override
+        public RadioAlert[] newArray(int size) {
+            return new RadioAlert[size];
+        }
+    };
+}
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index dcb363c..efddd1f 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -21,38 +21,4 @@
     namespace: "vcn"
     description: "Feature flag for enabling network metric monitor"
     bug: "282996138"
-}
-
-flag{
-    name: "validate_network_on_ipsec_loss"
-    namespace: "vcn"
-    description: "Trigger network validation when IPsec packet loss exceeds the threshold"
-    bug: "329139898"
-}
-
-flag{
-    name: "evaluate_ipsec_loss_on_lp_nc_change"
-    namespace: "vcn"
-    description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change"
-    bug: "323238888"
-}
-
-flag{
-    name: "enforce_main_user"
-    namespace: "vcn"
-    description: "Enforce main user to make VCN HSUM compatible"
-    bug: "310310661"
-    metadata {
-      purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag{
-    name: "handle_seq_num_leap"
-    namespace: "vcn"
-    description: "Do not report bad network when there is a suspected sequence number leap"
-    bug: "332598276"
-    metadata {
-      purpose: PURPOSE_BUGFIX
-    }
 }
\ No newline at end of file
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 479aa98..a894833 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -43,6 +44,8 @@
 
 import dalvik.system.VMRuntime;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -1273,6 +1276,47 @@
         public static final int VANILLA_ICE_CREAM = 35;
     }
 
+    /** @hide */
+    @IntDef(value = {
+        VERSION_CODES_FULL.BASE,
+        VERSION_CODES_FULL.BASE_1_1,
+        VERSION_CODES_FULL.CUPCAKE,
+        VERSION_CODES_FULL.DONUT,
+        VERSION_CODES_FULL.ECLAIR,
+        VERSION_CODES_FULL.ECLAIR_0_1,
+        VERSION_CODES_FULL.ECLAIR_MR1,
+        VERSION_CODES_FULL.FROYO,
+        VERSION_CODES_FULL.GINGERBREAD,
+        VERSION_CODES_FULL.GINGERBREAD_MR1,
+        VERSION_CODES_FULL.HONEYCOMB,
+        VERSION_CODES_FULL.HONEYCOMB_MR1,
+        VERSION_CODES_FULL.HONEYCOMB_MR2,
+        VERSION_CODES_FULL.ICE_CREAM_SANDWICH,
+        VERSION_CODES_FULL.ICE_CREAM_SANDWICH_MR1,
+        VERSION_CODES_FULL.JELLY_BEAN,
+        VERSION_CODES_FULL.JELLY_BEAN_MR1,
+        VERSION_CODES_FULL.JELLY_BEAN_MR2,
+        VERSION_CODES_FULL.KITKAT,
+        VERSION_CODES_FULL.KITKAT_WATCH,
+        VERSION_CODES_FULL.LOLLIPOP,
+        VERSION_CODES_FULL.LOLLIPOP_MR1,
+        VERSION_CODES_FULL.M,
+        VERSION_CODES_FULL.N,
+        VERSION_CODES_FULL.N_MR1,
+        VERSION_CODES_FULL.O,
+        VERSION_CODES_FULL.O_MR1,
+        VERSION_CODES_FULL.P,
+        VERSION_CODES_FULL.Q,
+        VERSION_CODES_FULL.R,
+        VERSION_CODES_FULL.S,
+        VERSION_CODES_FULL.S_V2,
+        VERSION_CODES_FULL.TIRAMISU,
+        VERSION_CODES_FULL.UPSIDE_DOWN_CAKE,
+        VERSION_CODES_FULL.VANILLA_ICE_CREAM,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SdkIntFull {}
+
     /**
      * Enumeration of the currently known SDK major and minor version codes.
      * The numbers increase for every release, and are guaranteed to be ordered
@@ -1290,6 +1334,208 @@
         // Use the last 5 digits for the minor version. This allows the
         // minor version to be set to CUR_DEVELOPMENT.
         private static final int SDK_INT_MULTIPLIER = 100000;
+
+        /**
+         * Android 1.0.
+         */
+        public static final int BASE = VERSION_CODES.BASE * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 2.0.
+         */
+        public static final int BASE_1_1 = VERSION_CODES.BASE_1_1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 3.0.
+         */
+        public static final int CUPCAKE = VERSION_CODES.CUPCAKE * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 4.0.
+         */
+        public static final int DONUT = VERSION_CODES.DONUT * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 5.0.
+         */
+        public static final int ECLAIR = VERSION_CODES.ECLAIR * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 6.0.
+         */
+        public static final int ECLAIR_0_1 = VERSION_CODES.ECLAIR_0_1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 7.0.
+         */
+        public static final int ECLAIR_MR1 = VERSION_CODES.ECLAIR_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 8.0.
+         */
+        public static final int FROYO = VERSION_CODES.FROYO * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 9.0.
+         */
+        public static final int GINGERBREAD = VERSION_CODES.GINGERBREAD * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 10.0.
+         */
+        public static final int GINGERBREAD_MR1 =
+                VERSION_CODES.GINGERBREAD_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 11.0.
+         */
+        public static final int HONEYCOMB = VERSION_CODES.HONEYCOMB * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 12.0.
+         */
+        public static final int HONEYCOMB_MR1 = VERSION_CODES.HONEYCOMB_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 13.0.
+         */
+        public static final int HONEYCOMB_MR2 = VERSION_CODES.HONEYCOMB_MR2 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 14.0.
+         */
+        public static final int ICE_CREAM_SANDWICH =
+                VERSION_CODES.ICE_CREAM_SANDWICH * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 15.0.
+         */
+        public static final int ICE_CREAM_SANDWICH_MR1 =
+                VERSION_CODES.ICE_CREAM_SANDWICH_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 16.0.
+         */
+        public static final int JELLY_BEAN = VERSION_CODES.JELLY_BEAN * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 17.0.
+         */
+        public static final int JELLY_BEAN_MR1 = VERSION_CODES.JELLY_BEAN_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 18.0.
+         */
+        public static final int JELLY_BEAN_MR2 = VERSION_CODES.JELLY_BEAN_MR2 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 19.0.
+         */
+        public static final int KITKAT = VERSION_CODES.KITKAT * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 20.0.
+         */
+        public static final int KITKAT_WATCH = VERSION_CODES.KITKAT_WATCH * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 21.0.
+         */
+        public static final int LOLLIPOP = VERSION_CODES.LOLLIPOP * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 22.0.
+         */
+        public static final int LOLLIPOP_MR1 = VERSION_CODES.LOLLIPOP_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 23.0.
+         */
+        public static final int M = VERSION_CODES.M * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 24.0.
+         */
+        public static final int N = VERSION_CODES.N * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 25.0.
+         */
+        public static final int N_MR1 = VERSION_CODES.N_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 26.0.
+         */
+        public static final int O = VERSION_CODES.O * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 27.0.
+         */
+        public static final int O_MR1 = VERSION_CODES.O_MR1 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 28.0.
+         */
+        public static final int P = VERSION_CODES.P * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 29.0.
+         */
+        public static final int Q = VERSION_CODES.Q * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 30.0.
+         */
+        public static final int R = VERSION_CODES.R * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 31.0.
+         */
+        public static final int S = VERSION_CODES.S * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 32.0.
+         */
+        public static final int S_V2 = VERSION_CODES.S_V2 * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 33.0.
+         */
+        public static final int TIRAMISU = VERSION_CODES.TIRAMISU * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 34.0.
+         */
+        public static final int UPSIDE_DOWN_CAKE =
+                VERSION_CODES.UPSIDE_DOWN_CAKE * SDK_INT_MULTIPLIER;
+
+        /**
+         * Android 35.0.
+         */
+        public static final int VANILLA_ICE_CREAM =
+                VERSION_CODES.VANILLA_ICE_CREAM * SDK_INT_MULTIPLIER;
+    }
+
+    /**
+     * Obtain the major version encoded in a VERSION_CODES_FULL value.
+     * This value is guaranteed to be non-negative.
+     *
+     * @return The major version encoded in a VERSION_CODES_FULL value
+     */
+    @FlaggedApi(Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME)
+    public static int getMajorSdkVersion(@SdkIntFull int sdkIntFull) {
+        return sdkIntFull / VERSION_CODES_FULL.SDK_INT_MULTIPLIER;
+    }
+
+    /**
+     * Obtain the minor version encoded in a VERSION_CODES_FULL value.
+     * This value is guaranteed to be non-negative.
+     *
+     * @return The minor version encoded in a VERSION_CODES_FULL value
+     */
+    @FlaggedApi(Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME)
+    public static int getMinorSdkVersion(@SdkIntFull int sdkIntFull) {
+        return sdkIntFull % VERSION_CODES_FULL.SDK_INT_MULTIPLIER;
     }
 
     /**
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index f82c822..769cbdd 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,18 +16,11 @@
 
 package android.os;
 
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Slog;
 
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -37,7 +30,7 @@
  * {@link android.app.Service} to its clients.  In particular, this:
  *
  * <ul>
- * <li> Keeps track of a set of registered {@link IInterface} objects,
+ * <li> Keeps track of a set of registered {@link IInterface} callbacks,
  * taking care to identify them through their underlying unique {@link IBinder}
  * (by calling {@link IInterface#asBinder IInterface.asBinder()}.
  * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
@@ -54,7 +47,7 @@
  * the registered clients, use {@link #beginBroadcast},
  * {@link #getBroadcastItem}, and {@link #finishBroadcast}.
  *
- * <p>If a registered interface's process goes away, this class will take
+ * <p>If a registered callback's process goes away, this class will take
  * care of automatically removing it from the list.  If you want to do
  * additional work in this situation, you can create a subclass that
  * implements the {@link #onCallbackDied} method.
@@ -63,310 +56,78 @@
 public class RemoteCallbackList<E extends IInterface> {
     private static final String TAG = "RemoteCallbackList";
 
-    private static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
-
-
-    /**
-     * @hide
-     */
-    @IntDef(prefix = {"FROZEN_CALLEE_POLICY_"}, value = {
-            FROZEN_CALLEE_POLICY_UNSET,
-            FROZEN_CALLEE_POLICY_ENQUEUE_ALL,
-            FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT,
-            FROZEN_CALLEE_POLICY_DROP,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface FrozenCalleePolicy {
-    }
-
-    /**
-     * Callbacks are invoked immediately regardless of the frozen state of the target process.
-     *
-     * Not recommended. Only exists for backward-compatibility. This represents the behavior up to
-     * SDK 35. Starting with SDK 36, clients should set a policy to govern callback invocations when
-     * recipients are frozen.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public static final int FROZEN_CALLEE_POLICY_UNSET = 0;
-
-    /**
-     * When the callback recipient's process is frozen, callbacks are enqueued so they're invoked
-     * after the recipient is unfrozen.
-     *
-     * This is commonly used when the recipient wants to receive all callbacks without losing any
-     * history, e.g. the recipient maintains a running count of events that occurred.
-     *
-     * Queued callbacks are invoked in the order they were originally broadcasted.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1;
-
-    /**
-     * When the callback recipient's process is frozen, only the most recent callback is enqueued,
-     * which is later invoked after the recipient is unfrozen.
-     *
-     * This can be used when only the most recent state matters, for instance when clients are
-     * listening to screen brightness changes.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2;
-
-    /**
-     * When the callback recipient's process is frozen, callbacks are suppressed as if they never
-     * happened.
-     *
-     * This could be useful in the case where the recipient wishes to react to callbacks only when
-     * they occur while the recipient is not frozen. For example, certain network events are only
-     * worth responding to if the response can be immediate. Another example is recipients having
-     * another way of getting the latest state once it's unfrozen. Therefore there is no need to
-     * save callbacks that happened while the recipient was frozen.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public static final int FROZEN_CALLEE_POLICY_DROP = 3;
-
     @UnsupportedAppUsage
-    /*package*/ ArrayMap<IBinder, Interface> mInterfaces = new ArrayMap<IBinder, Interface>();
+    /*package*/ ArrayMap<IBinder, Callback> mCallbacks
+            = new ArrayMap<IBinder, Callback>();
     private Object[] mActiveBroadcast;
     private int mBroadcastCount = -1;
     private boolean mKilled = false;
     private StringBuilder mRecentCallers;
 
-    private final @FrozenCalleePolicy int mFrozenCalleePolicy;
-    private final int mMaxQueueSize;
-
-    private final class Interface implements IBinder.DeathRecipient,
-            IBinder.FrozenStateChangeCallback {
-        final IBinder mBinder;
-        final E mInterface;
+    private final class Callback implements IBinder.DeathRecipient {
+        final E mCallback;
         final Object mCookie;
-        final Queue<Consumer<E>> mCallbackQueue;
-        int mCurrentState = IBinder.FrozenStateChangeCallback.STATE_UNFROZEN;
 
-        Interface(E callbackInterface, Object cookie) {
-            mBinder = callbackInterface.asBinder();
-            mInterface = callbackInterface;
+        Callback(E callback, Object cookie) {
+            mCallback = callback;
             mCookie = cookie;
-            mCallbackQueue = mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_ALL
-                || mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT
-                ? new ConcurrentLinkedQueue<>() : null;
-        }
-
-        @Override
-        public synchronized void onFrozenStateChanged(@NonNull IBinder who, int state) {
-            if (state == STATE_UNFROZEN && mCallbackQueue != null) {
-                while (!mCallbackQueue.isEmpty()) {
-                    Consumer<E> callback = mCallbackQueue.poll();
-                    callback.accept(mInterface);
-                }
-            }
-            mCurrentState = state;
-        }
-
-        void addCallback(@NonNull Consumer<E> callback) {
-            if (mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_UNSET) {
-                callback.accept(mInterface);
-                return;
-            }
-            synchronized (this) {
-                if (mCurrentState == STATE_UNFROZEN) {
-                    callback.accept(mInterface);
-                    return;
-                }
-                switch (mFrozenCalleePolicy) {
-                    case FROZEN_CALLEE_POLICY_ENQUEUE_ALL:
-                        if (mCallbackQueue.size() >= mMaxQueueSize) {
-                            mCallbackQueue.poll();
-                        }
-                        mCallbackQueue.offer(callback);
-                        break;
-                    case FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT:
-                        mCallbackQueue.clear();
-                        mCallbackQueue.offer(callback);
-                        break;
-                    case FROZEN_CALLEE_POLICY_DROP:
-                        // Do nothing. Just ignore the callback.
-                        break;
-                    case FROZEN_CALLEE_POLICY_UNSET:
-                        // Do nothing. Should have returned at the start of the method.
-                        break;
-                }
-            }
-        }
-
-        public void maybeSubscribeToFrozenCallback() throws RemoteException {
-            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
-                mBinder.addFrozenStateChangeCallback(this);
-            }
-        }
-
-        public void maybeUnsubscribeFromFrozenCallback() {
-            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
-                mBinder.removeFrozenStateChangeCallback(this);
-            }
         }
 
         public void binderDied() {
-            synchronized (mInterfaces) {
-                mInterfaces.remove(mBinder);
-                maybeUnsubscribeFromFrozenCallback();
+            synchronized (mCallbacks) {
+                mCallbacks.remove(mCallback.asBinder());
             }
-            onCallbackDied(mInterface, mCookie);
+            onCallbackDied(mCallback, mCookie);
         }
     }
 
     /**
-     * Builder for {@link RemoteCallbackList}.
-     *
-     * @param <E> The remote callback interface type.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public static final class Builder<E extends IInterface> {
-        private @FrozenCalleePolicy int mFrozenCalleePolicy;
-        private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
-
-        /**
-         * Creates a Builder for {@link RemoteCallbackList}.
-         *
-         * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
-         * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
-         * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
-         * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
-         */
-        public Builder(@FrozenCalleePolicy int frozenCalleePolicy) {
-            mFrozenCalleePolicy = frozenCalleePolicy;
-        }
-
-        /**
-         * Sets the max queue size.
-         *
-         * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
-         * recipient's process is frozen. Once the limit is reached, the oldest callback is dropped
-         * to keep the size under the limit. Should only be called for
-         * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
-         *
-         * @return This builder.
-         * @throws IllegalArgumentException if the maxQueueSize is not positive.
-         * @throws UnsupportedOperationException if frozenCalleePolicy is not
-         * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
-         */
-        public @NonNull Builder setMaxQueueSize(int maxQueueSize) {
-            if (maxQueueSize <= 0) {
-                throw new IllegalArgumentException("maxQueueSize must be positive");
-            }
-            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_ENQUEUE_ALL) {
-                throw new UnsupportedOperationException(
-                        "setMaxQueueSize can only be called for FROZEN_CALLEE_POLICY_ENQUEUE_ALL");
-            }
-            mMaxQueueSize = maxQueueSize;
-            return this;
-        }
-
-        /**
-         * Builds and returns a {@link RemoteCallbackList}.
-         *
-         * @return The built {@link RemoteCallbackList} object.
-         */
-        public @NonNull RemoteCallbackList<E> build() {
-            return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize);
-        }
-    }
-
-    /**
-     * Returns the frozen callee policy.
-     *
-     * @return The frozen callee policy.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public @FrozenCalleePolicy int getFrozenCalleePolicy() {
-        return mFrozenCalleePolicy;
-    }
-
-    /**
-     * Returns the max queue size.
-     *
-     * @return The max queue size.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public int getMaxQueueSize() {
-        return mMaxQueueSize;
-    }
-
-    /**
-     * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
-     * <pre>
-     * new RemoteCallbackList.Build(RemoteCallbackList.FROZEN_CALLEE_POLICY_UNSET).build()
-     * </pre>
-     */
-    public RemoteCallbackList() {
-        this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE);
-    }
-
-    /**
-     * Creates a RemoteCallbackList with the specified frozen callee policy.
-     *
-     * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
-     * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
-     * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
-     * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
-     *
-     * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
-     * recipient's process is frozen. Once the limit is reached, the oldest callbacks would be
-     * dropped to keep the size under limit. Ignored except for
-     * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
-     */
-    private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) {
-        mFrozenCalleePolicy = frozenCalleePolicy;
-        mMaxQueueSize = maxQueueSize;
-    }
-
-    /**
      * Simple version of {@link RemoteCallbackList#register(E, Object)}
      * that does not take a cookie object.
      */
-    public boolean register(E callbackInterface) {
-        return register(callbackInterface, null);
+    public boolean register(E callback) {
+        return register(callback, null);
     }
 
     /**
-     * Add a new interface to the list.  This interface will remain in the list
+     * Add a new callback to the list.  This callback will remain in the list
      * until a corresponding call to {@link #unregister} or its hosting process
-     * goes away.  If the interface was already registered (determined by
-     * checking to see if the {@link IInterface#asBinder callbackInterface.asBinder()}
-     * object is already in the list), then it will be replaced with the new interface.
+     * goes away. If the callback was already registered (determined by
+     * checking to see if the {@link IInterface#asBinder callback.asBinder()}
+     * object is already in the list), then it will be replaced with the new callback.
      * Registrations are not counted; a single call to {@link #unregister}
-     * will remove an interface after any number calls to register it.
+     * will remove a callback after any number calls to register it.
      *
-     * @param callbackInterface The callback interface to be added to the list.  Must
+     * @param callback The callback interface to be added to the list.  Must
      * not be null -- passing null here will cause a NullPointerException.
      * Most services will want to check for null before calling this with
      * an object given from a client, so that clients can't crash the
      * service with bad data.
      *
      * @param cookie Optional additional data to be associated with this
-     * interface.
+     * callback.
      *
-     * @return Returns true if the interface was successfully added to the list.
+     * @return Returns true if the callback was successfully added to the list.
      * Returns false if it was not added, either because {@link #kill} had
-     * previously been called or the interface's process has gone away.
+     * previously been called or the callback's process has gone away.
      *
      * @see #unregister
      * @see #kill
      * @see #onCallbackDied
      */
-    public boolean register(E callbackInterface, Object cookie) {
-        synchronized (mInterfaces) {
+    public boolean register(E callback, Object cookie) {
+        synchronized (mCallbacks) {
             if (mKilled) {
                 return false;
             }
             // Flag unusual case that could be caused by a leak. b/36778087
-            logExcessiveInterfaces();
-            IBinder binder = callbackInterface.asBinder();
+            logExcessiveCallbacks();
+            IBinder binder = callback.asBinder();
             try {
-                Interface i = new Interface(callbackInterface, cookie);
-                unregister(callbackInterface);
-                binder.linkToDeath(i, 0);
-                i.maybeSubscribeToFrozenCallback();
-                mInterfaces.put(binder, i);
+                Callback cb = new Callback(callback, cookie);
+                unregister(callback);
+                binder.linkToDeath(cb, 0);
+                mCallbacks.put(binder, cb);
                 return true;
             } catch (RemoteException e) {
                 return false;
@@ -375,28 +136,27 @@
     }
 
     /**
-     * Remove from the list an interface that was previously added with
+     * Remove from the list a callback that was previously added with
      * {@link #register}.  This uses the
-     * {@link IInterface#asBinder callbackInterface.asBinder()} object to correctly
+     * {@link IInterface#asBinder callback.asBinder()} object to correctly
      * find the previous registration.
      * Registrations are not counted; a single unregister call will remove
-     * an interface after any number calls to {@link #register} for it.
+     * a callback after any number calls to {@link #register} for it.
      *
-     * @param callbackInterface The interface to be removed from the list.  Passing
+     * @param callback The callback to be removed from the list.  Passing
      * null here will cause a NullPointerException, so you will generally want
      * to check for null before calling.
      *
-     * @return Returns true if the interface was found and unregistered.  Returns
-     * false if the given interface was not found on the list.
+     * @return Returns true if the callback was found and unregistered.  Returns
+     * false if the given callback was not found on the list.
      *
      * @see #register
      */
-    public boolean unregister(E callbackInterface) {
-        synchronized (mInterfaces) {
-            Interface i = mInterfaces.remove(callbackInterface.asBinder());
-            if (i != null) {
-                i.mInterface.asBinder().unlinkToDeath(i, 0);
-                i.maybeUnsubscribeFromFrozenCallback();
+    public boolean unregister(E callback) {
+        synchronized (mCallbacks) {
+            Callback cb = mCallbacks.remove(callback.asBinder());
+            if (cb != null) {
+                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
                 return true;
             }
             return false;
@@ -404,21 +164,20 @@
     }
 
     /**
-     * Disable this interface list.  All registered interfaces are unregistered,
+     * Disable this callback list.  All registered callbacks are unregistered,
      * and the list is disabled so that future calls to {@link #register} will
      * fail.  This should be used when a Service is stopping, to prevent clients
-     * from registering interfaces after it is stopped.
+     * from registering callbacks after it is stopped.
      *
      * @see #register
      */
     public void kill() {
-        synchronized (mInterfaces) {
-            for (int cbi = mInterfaces.size() - 1; cbi >= 0; cbi--) {
-                Interface i = mInterfaces.valueAt(cbi);
-                i.mInterface.asBinder().unlinkToDeath(i, 0);
-                i.maybeUnsubscribeFromFrozenCallback();
+        synchronized (mCallbacks) {
+            for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) {
+                Callback cb = mCallbacks.valueAt(cbi);
+                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
             }
-            mInterfaces.clear();
+            mCallbacks.clear();
             mKilled = true;
         }
     }
@@ -427,15 +186,15 @@
      * Old version of {@link #onCallbackDied(E, Object)} that
      * does not provide a cookie.
      */
-    public void onCallbackDied(E callbackInterface) {
+    public void onCallbackDied(E callback) {
     }
     
     /**
-     * Called when the process hosting an interface in the list has gone away.
+     * Called when the process hosting a callback in the list has gone away.
      * The default implementation calls {@link #onCallbackDied(E)}
      * for backwards compatibility.
      * 
-     * @param callbackInterface The interface whose process has died.  Note that, since
+     * @param callback The callback whose process has died.  Note that, since
      * its process has died, you can not make any calls on to this interface.
      * You can, however, retrieve its IBinder and compare it with another
      * IBinder to see if it is the same object.
@@ -444,15 +203,13 @@
      * 
      * @see #register
      */
-    public void onCallbackDied(E callbackInterface, Object cookie) {
-        onCallbackDied(callbackInterface);
+    public void onCallbackDied(E callback, Object cookie) {
+        onCallbackDied(callback);
     }
 
     /**
-     * Use {@link #broadcast(Consumer)} instead to ensure proper handling of frozen processes.
-     *
-     * Prepare to start making calls to the currently registered interfaces.
-     * This creates a copy of the interface list, which you can retrieve items
+     * Prepare to start making calls to the currently registered callbacks.
+     * This creates a copy of the callback list, which you can retrieve items
      * from using {@link #getBroadcastItem}.  Note that only one broadcast can
      * be active at a time, so you must be sure to always call this from the
      * same thread (usually by scheduling with {@link Handler}) or
@@ -462,56 +219,44 @@
      * <p>A typical loop delivering a broadcast looks like this:
      *
      * <pre>
-     * int i = interfaces.beginBroadcast();
+     * int i = callbacks.beginBroadcast();
      * while (i &gt; 0) {
      *     i--;
      *     try {
-     *         interfaces.getBroadcastItem(i).somethingHappened();
+     *         callbacks.getBroadcastItem(i).somethingHappened();
      *     } catch (RemoteException e) {
      *         // The RemoteCallbackList will take care of removing
      *         // the dead object for us.
      *     }
      * }
-     * interfaces.finishBroadcast();</pre>
+     * callbacks.finishBroadcast();</pre>
      *
-     * Note that this method is only supported for {@link #FROZEN_CALLEE_POLICY_UNSET}. For other
-     * policies use {@link #broadcast(Consumer)} instead.
-     *
-     * @return Returns the number of interfaces in the broadcast, to be used
+     * @return Returns the number of callbacks in the broadcast, to be used
      * with {@link #getBroadcastItem} to determine the range of indices you
      * can supply.
      *
-     * @throws UnsupportedOperationException if an frozen callee policy is set.
-     *
      * @see #getBroadcastItem
      * @see #finishBroadcast
      */
     public int beginBroadcast() {
-        if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
-            throw new UnsupportedOperationException();
-        }
-        return beginBroadcastInternal();
-    }
-
-    private int beginBroadcastInternal() {
-        synchronized (mInterfaces) {
+        synchronized (mCallbacks) {
             if (mBroadcastCount > 0) {
                 throw new IllegalStateException(
                         "beginBroadcast() called while already in a broadcast");
             }
             
-            final int n = mBroadcastCount = mInterfaces.size();
-            if (n <= 0) {
+            final int N = mBroadcastCount = mCallbacks.size();
+            if (N <= 0) {
                 return 0;
             }
             Object[] active = mActiveBroadcast;
-            if (active == null || active.length < n) {
-                mActiveBroadcast = active = new Object[n];
+            if (active == null || active.length < N) {
+                mActiveBroadcast = active = new Object[N];
             }
-            for (int i = 0; i < n; i++) {
-                active[i] = mInterfaces.valueAt(i);
+            for (int i=0; i<N; i++) {
+                active[i] = mCallbacks.valueAt(i);
             }
-            return n;
+            return N;
         }
     }
 
@@ -522,23 +267,24 @@
      * calling {@link #finishBroadcast}.
      *
      * <p>Note that it is possible for the process of one of the returned
-     * interfaces to go away before you call it, so you will need to catch
+     * callbacks to go away before you call it, so you will need to catch
      * {@link RemoteException} when calling on to the returned object.
-     * The interface list itself, however, will take care of unregistering
+     * The callback list itself, however, will take care of unregistering
      * these objects once it detects that it is no longer valid, so you can
      * handle such an exception by simply ignoring it.
      *
-     * @param index Which of the registered interfaces you would like to
+     * @param index Which of the registered callbacks you would like to
      * retrieve.  Ranges from 0 to {@link #beginBroadcast}-1, inclusive.
      *
-     * @return Returns the interface that you can call.  This will always be non-null.
+     * @return Returns the callback interface that you can call.  This will
+     * always be non-null.
      *
      * @see #beginBroadcast
      */
     public E getBroadcastItem(int index) {
-        return ((Interface) mActiveBroadcast[index]).mInterface;
+        return ((Callback)mActiveBroadcast[index]).mCallback;
     }
-
+    
     /**
      * Retrieve the cookie associated with the item
      * returned by {@link #getBroadcastItem(int)}.
@@ -546,7 +292,7 @@
      * @see #getBroadcastItem
      */
     public Object getBroadcastCookie(int index) {
-        return ((Interface) mActiveBroadcast[index]).mCookie;
+        return ((Callback)mActiveBroadcast[index]).mCookie;
     }
 
     /**
@@ -557,7 +303,7 @@
      * @see #beginBroadcast
      */
     public void finishBroadcast() {
-        synchronized (mInterfaces) {
+        synchronized (mCallbacks) {
             if (mBroadcastCount < 0) {
                 throw new IllegalStateException(
                         "finishBroadcast() called outside of a broadcast");
@@ -576,35 +322,16 @@
     }
 
     /**
-     * Performs {@code callback} on each registered interface.
-     *
-     * This is equivalent to #beginBroadcast, followed by iterating over the items using
-     * #getBroadcastItem and then @finishBroadcast, except that this method supports
-     * frozen callee policies.
-     */
-    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    public void broadcast(@NonNull Consumer<E> callback) {
-        int itemCount = beginBroadcastInternal();
-        try {
-            for (int i = 0; i < itemCount; i++) {
-                ((Interface) mActiveBroadcast[i]).addCallback(callback);
-            }
-        } finally {
-            finishBroadcast();
-        }
-    }
-
-    /**
-     * Performs {@code callback} for each cookie associated with an interface, calling
+     * Performs {@code action} on each callback, calling
      * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
      *
      * @hide
      */
-    public <C> void broadcastForEachCookie(Consumer<C> callback) {
+    public void broadcast(Consumer<E> action) {
         int itemCount = beginBroadcast();
         try {
             for (int i = 0; i < itemCount; i++) {
-                callback.accept((C) getBroadcastCookie(i));
+                action.accept(getBroadcastItem(i));
             }
         } finally {
             finishBroadcast();
@@ -612,16 +339,33 @@
     }
 
     /**
-     * Performs {@code callback} on each interface and associated cookie, calling {@link
+     * Performs {@code action} for each cookie associated with a callback, calling
+     * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
+     *
+     * @hide
+     */
+    public <C> void broadcastForEachCookie(Consumer<C> action) {
+        int itemCount = beginBroadcast();
+        try {
+            for (int i = 0; i < itemCount; i++) {
+                action.accept((C) getBroadcastCookie(i));
+            }
+        } finally {
+            finishBroadcast();
+        }
+    }
+
+    /**
+     * Performs {@code action} on each callback and associated cookie, calling {@link
      * #beginBroadcast()}/{@link #finishBroadcast()} before/after looping.
      *
      * @hide
      */
-    public <C> void broadcast(BiConsumer<E, C> callback) {
+    public <C> void broadcast(BiConsumer<E, C> action) {
         int itemCount = beginBroadcast();
         try {
             for (int i = 0; i < itemCount; i++) {
-                callback.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
+                action.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
             }
         } finally {
             finishBroadcast();
@@ -629,10 +373,10 @@
     }
 
     /**
-     * Returns the number of registered interfaces. Note that the number of registered
-     * interfaces may differ from the value returned by {@link #beginBroadcast()} since
-     * the former returns the number of interfaces registered at the time of the call
-     * and the second the number of interfaces to which the broadcast will be delivered.
+     * Returns the number of registered callbacks. Note that the number of registered
+     * callbacks may differ from the value returned by {@link #beginBroadcast()} since
+     * the former returns the number of callbacks registered at the time of the call
+     * and the second the number of callback to which the broadcast will be delivered.
      * <p>
      * This function is useful to decide whether to schedule a broadcast if this
      * requires doing some work which otherwise would not be performed.
@@ -641,39 +385,39 @@
      * @return The size.
      */
     public int getRegisteredCallbackCount() {
-        synchronized (mInterfaces) {
+        synchronized (mCallbacks) {
             if (mKilled) {
                 return 0;
             }
-            return mInterfaces.size();
+            return mCallbacks.size();
         }
     }
 
     /**
-     * Return a currently registered interface.  Note that this is
+     * Return a currently registered callback.  Note that this is
      * <em>not</em> the same as {@link #getBroadcastItem} and should not be used
-     * interchangeably with it.  This method returns the registered interface at the given
+     * interchangeably with it.  This method returns the registered callback at the given
      * index, not the current broadcast state.  This means that it is not itself thread-safe:
      * any call to {@link #register} or {@link #unregister} will change these indices, so you
      * must do your own thread safety between these to protect from such changes.
      *
-     * @param index Index of which interface registration to return, from 0 to
+     * @param index Index of which callback registration to return, from 0 to
      * {@link #getRegisteredCallbackCount()} - 1.
      *
-     * @return Returns whatever interface is associated with this index, or null if
+     * @return Returns whatever callback is associated with this index, or null if
      * {@link #kill()} has been called.
      */
     public E getRegisteredCallbackItem(int index) {
-        synchronized (mInterfaces) {
+        synchronized (mCallbacks) {
             if (mKilled) {
                 return null;
             }
-            return mInterfaces.valueAt(index).mInterface;
+            return mCallbacks.valueAt(index).mCallback;
         }
     }
 
     /**
-     * Return any cookie associated with a currently registered interface.  Note that this is
+     * Return any cookie associated with a currently registered callback.  Note that this is
      * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
      * interchangeably with it.  This method returns the current cookie registered at the given
      * index, not the current broadcast state.  This means that it is not itself thread-safe:
@@ -687,25 +431,25 @@
      * {@link #kill()} has been called.
      */
     public Object getRegisteredCallbackCookie(int index) {
-        synchronized (mInterfaces) {
+        synchronized (mCallbacks) {
             if (mKilled) {
                 return null;
             }
-            return mInterfaces.valueAt(index).mCookie;
+            return mCallbacks.valueAt(index).mCookie;
         }
     }
 
     /** @hide */
     public void dump(PrintWriter pw, String prefix) {
-        synchronized (mInterfaces) {
-            pw.print(prefix); pw.print("callbacks: "); pw.println(mInterfaces.size());
+        synchronized (mCallbacks) {
+            pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
             pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
             pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
         }
     }
 
-    private void logExcessiveInterfaces() {
-        final long size = mInterfaces.size();
+    private void logExcessiveCallbacks() {
+        final long size = mCallbacks.size();
         final long TOO_MANY = 3000;
         final long MAX_CHARS = 1000;
         if (size >= TOO_MANY) {
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 37a91e7..b384b66 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -58,7 +58,6 @@
     void onSuggestedReplySent(String key, in CharSequence reply, int source);
     void onActionClicked(String key, in Notification.Action action, int source);
     void onNotificationClicked(String key);
-    // @deprecated changing allowed adjustments is no longer supported.
     void onAllowedAdjustmentsChanged();
     void onNotificationFeedbackReceived(String key, in NotificationRankingUpdate update, in Bundle feedback);
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 7b7058e..091b25a 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -319,10 +319,7 @@
      * their notifications the assistant can modify.
      * <p> Query {@link NotificationManager#getAllowedAssistantAdjustments()} to see what
      * {@link Adjustment adjustments} you are currently allowed to make.</p>
-     *
-     * @deprecated changing allowed adjustments is no longer supported.
      */
-    @Deprecated
     public void onAllowedAdjustmentsChanged() {
     }
 
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 0dec13f..e254bf3 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -73,8 +73,11 @@
 public abstract class Layout {
 
     // These should match the constants in framework/base/libs/hwui/hwui/DrawTextFunctor.h
-    private static final float HIGH_CONTRAST_TEXT_BORDER_WIDTH_MIN_PX = 4f;
-    private static final float HIGH_CONTRAST_TEXT_BORDER_WIDTH_FACTOR = 0.2f;
+    private static final float HIGH_CONTRAST_TEXT_BORDER_WIDTH_MIN_PX = 0f;
+    private static final float HIGH_CONTRAST_TEXT_BORDER_WIDTH_FACTOR = 0f;
+    private static final float HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_DP = 5f;
+    // since we're not using soft light yet, this needs to be much lower than the spec'd 0.8
+    private static final float HIGH_CONTRAST_TEXT_BACKGROUND_ALPHA_PERCENTAGE = 0.5f;
 
     /** @hide */
     @IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
@@ -1025,11 +1028,18 @@
 
         var padding = Math.max(HIGH_CONTRAST_TEXT_BORDER_WIDTH_MIN_PX,
                 mPaint.getTextSize() * HIGH_CONTRAST_TEXT_BORDER_WIDTH_FACTOR);
+        var cornerRadius = mPaint.density * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_DP;
+
+        // We set the alpha on the color itself instead of Paint.setAlpha(), because that function
+        // actually mutates the color in... *ehem* very strange ways. Also the color might get reset
+        // for various reasons, which also resets the alpha.
+        var white = Color.argb(HIGH_CONTRAST_TEXT_BACKGROUND_ALPHA_PERCENTAGE, 1f, 1f, 1f);
+        var black = Color.argb(HIGH_CONTRAST_TEXT_BACKGROUND_ALPHA_PERCENTAGE, 0f, 0f, 0f);
 
         var originalTextColor = mPaint.getColor();
         var bgPaint = mWorkPlainPaint;
         bgPaint.reset();
-        bgPaint.setColor(isHighContrastTextDark(originalTextColor) ? Color.WHITE : Color.BLACK);
+        bgPaint.setColor(isHighContrastTextDark(originalTextColor) ? white : black);
         bgPaint.setStyle(Paint.Style.FILL);
 
         int start = getLineStart(firstLine);
@@ -1082,7 +1092,12 @@
                     private void drawRect() {
                         if (!mLineBackground.isEmpty()) {
                             mLineBackground.inset(-padding, -padding);
-                            canvas.drawRect(mLineBackground, bgPaint);
+                            canvas.drawRoundRect(
+                                    mLineBackground,
+                                    cornerRadius,
+                                    cornerRadius,
+                                    bgPaint
+                            );
                         }
                     }
 
@@ -1104,7 +1119,7 @@
                         if (hasColorChanged) {
                             mLastColor = textColor;
 
-                            return isHighContrastTextDark(textColor) ? Color.WHITE : Color.BLACK;
+                            return isHighContrastTextDark(textColor) ? white : black;
                         }
 
                         return bgPaint.getColor();
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 8a8022c..e940e55bd 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -21,6 +21,7 @@
 import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API;
 
 import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API;
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_HAS_ARR_SUPPORT;
 
 import android.Manifest;
 import android.annotation.FlaggedApi;
@@ -1266,6 +1267,18 @@
     }
 
     /**
+     * Returns whether display supports adaptive refresh rate or not.
+     */
+    // TODO(b/372526856) Add a link to the documentation for ARR.
+    @FlaggedApi(FLAG_ENABLE_HAS_ARR_SUPPORT)
+    public boolean hasArrSupport() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            return mDisplayInfo.hasArrSupport;
+        }
+    }
+
+    /**
      * <p> Returns true if the connected display can be switched into a mode with minimal
      * post processing. </p>
      *
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index cac3e3c..26fce90 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -198,6 +198,12 @@
     public float renderFrameRate;
 
     /**
+     * If {@code true} this Display supports adaptive refresh rates.
+     * // TODO(b/372526856) Add a link to the documentation for ARR.
+     */
+    public boolean hasArrSupport;
+
+    /**
      * The default display mode.
      */
     public int defaultModeId;
@@ -436,6 +442,7 @@
                 && rotation == other.rotation
                 && modeId == other.modeId
                 && renderFrameRate == other.renderFrameRate
+                && hasArrSupport == other.hasArrSupport
                 && defaultModeId == other.defaultModeId
                 && userPreferredModeId == other.userPreferredModeId
                 && Arrays.equals(supportedModes, other.supportedModes)
@@ -497,6 +504,7 @@
         rotation = other.rotation;
         modeId = other.modeId;
         renderFrameRate = other.renderFrameRate;
+        hasArrSupport = other.hasArrSupport;
         defaultModeId = other.defaultModeId;
         userPreferredModeId = other.userPreferredModeId;
         supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
@@ -553,6 +561,7 @@
         rotation = source.readInt();
         modeId = source.readInt();
         renderFrameRate = source.readFloat();
+        hasArrSupport = source.readBoolean();
         defaultModeId = source.readInt();
         userPreferredModeId = source.readInt();
         int nModes = source.readInt();
@@ -626,6 +635,7 @@
         dest.writeInt(rotation);
         dest.writeInt(modeId);
         dest.writeFloat(renderFrameRate);
+        dest.writeBoolean(hasArrSupport);
         dest.writeInt(defaultModeId);
         dest.writeInt(userPreferredModeId);
         dest.writeInt(supportedModes.length);
@@ -871,6 +881,8 @@
         sb.append(modeId);
         sb.append(", renderFrameRate ");
         sb.append(renderFrameRate);
+        sb.append(", hasArrSupport ");
+        sb.append(hasArrSupport);
         sb.append(", defaultMode ");
         sb.append(defaultModeId);
         sb.append(", userPreferredModeId ");
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index d08873c..59c6653 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -22,6 +22,7 @@
 import static android.view.InsetsControllerProto.STATE;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.InsetsSource.ID_IME_CAPTION_BAR;
+import static android.view.ViewProtoLogGroups.IME_INSETS_CONTROLLER;
 import static android.view.WindowInsets.Type.FIRST;
 import static android.view.WindowInsets.Type.LAST;
 import static android.view.WindowInsets.Type.all;
@@ -69,6 +70,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.ImeTracing;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.function.TriFunction;
 
 import java.io.PrintWriter;
@@ -1920,6 +1922,8 @@
         final @InsetsType int requestedVisibleTypes =
                 (mRequestedVisibleTypes & ~mask) | (visibleTypes & mask);
         if (mRequestedVisibleTypes != requestedVisibleTypes) {
+            ProtoLog.d(IME_INSETS_CONTROLLER, "Setting requestedVisibleTypes to %d (was %d)",
+                    requestedVisibleTypes, mRequestedVisibleTypes);
             mRequestedVisibleTypes = requestedVisibleTypes;
         }
     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 19e244a..e6de478 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1810,6 +1810,7 @@
         public DisplayMode[] supportedDisplayModes;
         public int activeDisplayModeId;
         public float renderFrameRate;
+        public boolean hasArrSupport;
 
         public int[] supportedColorModes;
         public int activeColorMode;
@@ -1827,6 +1828,7 @@
                     + "supportedDisplayModes=" + Arrays.toString(supportedDisplayModes)
                     + ", activeDisplayModeId=" + activeDisplayModeId
                     + ", renderFrameRate=" + renderFrameRate
+                    + ", hasArrSupport=" + hasArrSupport
                     + ", supportedColorModes=" + Arrays.toString(supportedColorModes)
                     + ", activeColorMode=" + activeColorMode
                     + ", hdrCapabilities=" + hdrCapabilities
@@ -1846,13 +1848,14 @@
                 && Arrays.equals(supportedColorModes, that.supportedColorModes)
                 && activeColorMode == that.activeColorMode
                 && Objects.equals(hdrCapabilities, that.hdrCapabilities)
-                && preferredBootDisplayMode == that.preferredBootDisplayMode;
+                && preferredBootDisplayMode == that.preferredBootDisplayMode
+                && hasArrSupport == that.hasArrSupport;
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId,
-                    renderFrameRate, activeColorMode, hdrCapabilities);
+                    renderFrameRate, activeColorMode, hdrCapabilities, hasArrSupport);
         }
     }
 
diff --git a/core/java/android/view/ViewProtoLogGroups.java b/core/java/android/view/ViewProtoLogGroups.java
new file mode 100644
index 0000000..099f761
--- /dev/null
+++ b/core/java/android/view/ViewProtoLogGroups.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.view.inputmethod.Flags;
+
+import com.android.internal.protolog.ProtoLogGroup;
+
+import java.util.UUID;
+
+/**
+ * Defines logging groups for ProtoLog.
+ *
+ * This file is used by the ProtoLogTool to generate optimized logging code. All of its dependencies
+ * must be included in services.core.wm.protologgroups build target.
+ *
+ * @hide
+ */
+final class ViewProtoLogGroups {
+    final static ProtoLogGroup IME_INSETS_CONTROLLER = new ProtoLogGroup(
+        "IME_INSETS_CONTROLLER", "InsetsController", Flags.refactorInsetsController());
+
+    final static ProtoLogGroup[] ALL_GROUPS = {
+        IME_INSETS_CONTROLLER
+    };
+}
+
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b921213..182ed1e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -279,6 +279,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneFallbackEventHandler;
+import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
@@ -1282,6 +1283,8 @@
         mIsStylusPointerIconEnabled =
                 InputSettings.isStylusPointerIconEnabled(mContext);
 
+        initializeProtoLogInProcess();
+
         String processorOverrideName = context.getResources().getString(
                                     R.string.config_inputEventCompatProcessorOverrideClassName);
         if (processorOverrideName.isEmpty()) {
@@ -6971,9 +6974,7 @@
                     handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj);
                     break;
                 case MSG_PAUSED_FOR_SYNC_TIMEOUT:
-                    Log.e(mTag, "Timedout waiting to unpause for sync");
-                    mNumPausedForSync = 0;
-                    scheduleTraversals();
+                    resumeAfterSyncTimeout();
                     break;
                 case MSG_CHECK_INVALIDATION_IDLE: {
                     long delta;
@@ -12777,6 +12778,15 @@
         activeSurfaceSyncGroup.addTransaction(t);
     }
 
+    /**
+     * Resume rendering after being paused for sync due to a timeout.
+     */
+    private void resumeAfterSyncTimeout() {
+        Log.e(mTag, "Timedout waiting to unpause for sync mNumPausedForSync=" + mNumPausedForSync);
+        mNumPausedForSync = 0;
+        scheduleTraversals();
+    }
+
     @Override
     public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() {
         boolean newSyncGroup = false;
@@ -12804,6 +12814,16 @@
                 }
             });
             newSyncGroup = true;
+
+            // If the sync group is marked ready by a timeout, check if rendering is paused and
+            // if it is, resume rendering and trigger a traversal.
+            mActiveSurfaceSyncGroup.addSyncCompleteCallback(mExecutor, () -> {
+                if (mActiveSurfaceSyncGroup != null
+                        && mActiveSurfaceSyncGroup.isComplete() && mNumPausedForSync > 0) {
+                    mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
+                    resumeAfterSyncTimeout();
+                }
+            });
         }
 
         Trace.instant(Trace.TRACE_TAG_VIEW,
@@ -12818,12 +12838,20 @@
             }
         }
 
-        mNumPausedForSync++;
-        mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
-        mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT,
-                1000 * Build.HW_TIMEOUT_MULTIPLIER);
+        // The sync group can be marked ready by a timeout. This makes incrementing
+        // mNumPausedForSync racy. Here we check if the sync group is complete and
+        // if it is then we don't pause for syncing.
+        if (!mActiveSurfaceSyncGroup.isComplete()) {
+            mNumPausedForSync++;
+            mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
+            mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT,
+                    1000 * Build.HW_TIMEOUT_MULTIPLIER);
+        } else {
+            Log.d(mTag, "Active sync group is already completed "
+                    + mActiveSurfaceSyncGroup.getName());
+        }
         return mActiveSurfaceSyncGroup;
-    };
+    }
 
     private final Executor mSimpleExecutor = Runnable::run;
 
@@ -13378,4 +13406,13 @@
 
         mCurrentColorMode = colorMode;
     }
+
+    private static boolean sProtoLogInitialized = false;
+
+    private void initializeProtoLogInProcess() {
+        if (!sProtoLogInitialized) {
+            ProtoLog.init(ViewProtoLogGroups.ALL_GROUPS);
+            sProtoLogInitialized = true;
+        }
+    }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1e5c6d8..47fc437 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2352,6 +2352,13 @@
      * {@link #RESULT_HIDDEN}.
      * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note:
      * this does not return result of the request. For result use {@param resultReceiver} instead.
+     *
+     * @deprecated The {@link ResultReceiver} is not a reliable way of determining whether the
+     * Input Method is actually shown or hidden. If result is needed, use
+     * {@link android.view.WindowInsetsController#show} instead and set a
+     * {@link View.OnApplyWindowInsetsListener} and verify the provided {@link WindowInsets} for
+     * the visibility of IME. If result is not needed, use {@link #showSoftInput(View, int)}
+     * instead.
      */
     public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
         return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT);
@@ -2399,6 +2406,14 @@
                                 & WindowInsets.Type.ime()) == 0) {
                     ImeTracker.forLogging().onProgress(statsToken,
                             ImeTracker.PHASE_CLIENT_NO_ONGOING_USER_ANIMATION);
+                    if (resultReceiver != null) {
+                        final boolean imeReqVisible =
+                                (viewRootImpl.getInsetsController().getRequestedVisibleTypes()
+                                        & WindowInsets.Type.ime()) != 0;
+                        resultReceiver.send(
+                                imeReqVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+                                        : InputMethodManager.RESULT_SHOWN, null);
+                    }
                     // TODO(b/322992891) handle case of SHOW_IMPLICIT
                     viewRootImpl.getInsetsController().show(WindowInsets.Type.ime(),
                             false /* fromIme */, statsToken);
@@ -2531,6 +2546,13 @@
      * {@link #RESULT_HIDDEN}.
      * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note:
      * this does not return result of the request. For result use {@param resultReceiver} instead.
+     *
+     * @deprecated The {@link ResultReceiver} is not a reliable way of determining whether the
+     * Input Method is actually shown or hidden. If result is needed, use
+     * {@link android.view.WindowInsetsController#hide} instead and set a
+     * {@link View.OnApplyWindowInsetsListener} and verify the provided {@link WindowInsets} for
+     * the visibility of IME. If result is not needed, use
+     * {@link #hideSoftInputFromView(View, int)} instead.
      */
     public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
             ResultReceiver resultReceiver) {
@@ -2569,6 +2591,14 @@
                 // TODO(b/322992891) handle case of HIDE_IMPLICIT_ONLY
                 final var viewRootImpl = servedView.getViewRootImpl();
                 if (viewRootImpl != null) {
+                    if (resultReceiver != null) {
+                        final boolean imeReqVisible =
+                                (viewRootImpl.getInsetsController().getRequestedVisibleTypes()
+                                        & WindowInsets.Type.ime()) != 0;
+                        resultReceiver.send(
+                                !imeReqVisible ? InputMethodManager.RESULT_UNCHANGED_HIDDEN
+                                        : InputMethodManager.RESULT_HIDDEN, null);
+                    }
                     viewRootImpl.getInsetsController().hide(WindowInsets.Type.ime());
                 }
                 return true;
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index bae8aff..aa4927e 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -73,6 +73,17 @@
 }
 
 flag {
+    name: "consistent_get_current_input_method_info"
+    namespace: "input_method"
+    description: "Use BindingController as the source of truth in getCurrentInputMethodInfo"
+    bug: "355034523"
+    is_fixed_read_only: true
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "ime_switcher_revamp"
     is_exported: true
     namespace: "input_method"
diff --git a/core/java/android/widget/RemoteCollectionItemsAdapter.java b/core/java/android/widget/RemoteCollectionItemsAdapter.java
index 9b396ae..fc09f88 100644
--- a/core/java/android/widget/RemoteCollectionItemsAdapter.java
+++ b/core/java/android/widget/RemoteCollectionItemsAdapter.java
@@ -40,13 +40,15 @@
     private RemoteCollectionItems mItems;
     private InteractionHandler mInteractionHandler;
     private ColorResources mColorResources;
+    private boolean mOnLightBackground;
 
     private SparseIntArray mLayoutIdToViewType;
 
     RemoteCollectionItemsAdapter(
             @NonNull RemoteCollectionItems items,
             @NonNull InteractionHandler interactionHandler,
-            @NonNull ColorResources colorResources) {
+            @NonNull ColorResources colorResources,
+            boolean onLightBackground) {
         // View type count can never increase after an adapter has been set on a ListView.
         // Additionally, decreasing it could inhibit view recycling if the count were to back and
         // forth between 3-2-3-2 for example. Therefore, the view type count, should be fixed for
@@ -56,6 +58,7 @@
         mItems = items;
         mInteractionHandler = interactionHandler;
         mColorResources = colorResources;
+        mOnLightBackground = onLightBackground;
 
         initLayoutIdToViewType();
     }
@@ -68,7 +71,8 @@
     void setData(
             @NonNull RemoteCollectionItems items,
             @NonNull InteractionHandler interactionHandler,
-            @NonNull ColorResources colorResources) {
+            @NonNull ColorResources colorResources,
+            boolean onLightBackground) {
         if (mViewTypeCount < items.getViewTypeCount()) {
             throw new IllegalArgumentException(
                     "RemoteCollectionItemsAdapter cannot increase view type count after creation");
@@ -77,6 +81,7 @@
         mItems = items;
         mInteractionHandler = interactionHandler;
         mColorResources = colorResources;
+        mOnLightBackground = onLightBackground;
 
         initLayoutIdToViewType();
 
@@ -184,6 +189,7 @@
                 : new AppWidgetHostView.AdapterChildHostView(parent.getContext());
         newView.setInteractionHandler(mInteractionHandler);
         newView.setColorResourcesNoReapply(mColorResources);
+        newView.setOnLightBackground(mOnLightBackground);
         newView.updateAppWidget(item);
         return newView;
     }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index d7b5211..9b6311f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1248,6 +1248,7 @@
 
             AdapterView adapterView = (AdapterView) target;
             Adapter adapter = adapterView.getAdapter();
+            boolean onLightBackground = hasFlags(FLAG_USE_LIGHT_BACKGROUND_LAYOUT);
             // We can reuse the adapter if it's a RemoteCollectionItemsAdapter and the view type
             // count hasn't increased. Note that AbsListView allocates a fixed size array for view
             // recycling in setAdapter, so we must call setAdapter again if the number of view types
@@ -1255,8 +1256,12 @@
             if (adapter instanceof RemoteCollectionItemsAdapter
                     && adapter.getViewTypeCount() >= items.getViewTypeCount()) {
                 try {
-                    ((RemoteCollectionItemsAdapter) adapter).setData(
-                            items, params.handler, params.colorResources);
+                    ((RemoteCollectionItemsAdapter) adapter)
+                            .setData(
+                                    items,
+                                    params.handler,
+                                    params.colorResources,
+                                    onLightBackground);
                 } catch (Throwable throwable) {
                     // setData should never failed with the validation in the items builder, but if
                     // it does, catch and rethrow.
@@ -1266,8 +1271,9 @@
             }
 
             try {
-                adapterView.setAdapter(new RemoteCollectionItemsAdapter(items,
-                        params.handler, params.colorResources));
+                adapterView.setAdapter(
+                        new RemoteCollectionItemsAdapter(
+                                items, params.handler, params.colorResources, onLightBackground));
             } catch (Throwable throwable) {
                 // This could throw if the AdapterView somehow doesn't accept BaseAdapter due to
                 // a type error.
diff --git a/core/java/android/window/BackEvent.java b/core/java/android/window/BackEvent.java
index d3733b7..23e572f 100644
--- a/core/java/android/window/BackEvent.java
+++ b/core/java/android/window/BackEvent.java
@@ -16,8 +16,13 @@
 
 package android.window;
 
+import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_TIMESTAMP_API;
+import static com.android.window.flags.Flags.predictiveBackTimestampApi;
+
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
+import android.util.TimeUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -44,18 +49,25 @@
     private final float mTouchX;
     private final float mTouchY;
     private final float mProgress;
+    private final long mFrameTime;
 
     @SwipeEdge
     private final int mSwipeEdge;
 
     /** @hide */
     public static BackEvent fromBackMotionEvent(BackMotionEvent backMotionEvent) {
-        return new BackEvent(backMotionEvent.getTouchX(), backMotionEvent.getTouchY(),
-                backMotionEvent.getProgress(), backMotionEvent.getSwipeEdge());
+        if (predictiveBackTimestampApi()) {
+            return new BackEvent(backMotionEvent.getTouchX(), backMotionEvent.getTouchY(),
+                    backMotionEvent.getProgress(), backMotionEvent.getSwipeEdge(),
+                    backMotionEvent.getFrameTime());
+        } else {
+            return new BackEvent(backMotionEvent.getTouchX(), backMotionEvent.getTouchY(),
+                    backMotionEvent.getProgress(), backMotionEvent.getSwipeEdge());
+        }
     }
 
     /**
-     * Creates a new {@link BackEvent} instance.
+     * Creates a new {@link BackEvent} instance with the current uptime as frame time.
      *
      * @param touchX Absolute X location of the touch point of this event.
      * @param touchY Absolute Y location of the touch point of this event.
@@ -67,6 +79,26 @@
         mTouchY = touchY;
         mProgress = progress;
         mSwipeEdge = swipeEdge;
+        mFrameTime = System.nanoTime() / TimeUtils.NANOS_PER_MS;
+    }
+
+    /**
+     * Creates a new {@link BackEvent} instance.
+     *
+     * @param touchX Absolute X location of the touch point of this event.
+     * @param touchY Absolute Y location of the touch point of this event.
+     * @param progress Value between 0 and 1 on how far along the back gesture is.
+     * @param swipeEdge Indicates which edge the swipe starts from.
+     * @param frameTime frame time of the back event.
+     */
+    @FlaggedApi(FLAG_PREDICTIVE_BACK_TIMESTAMP_API)
+    public BackEvent(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge,
+            long frameTime) {
+        mTouchX = touchX;
+        mTouchY = touchY;
+        mProgress = progress;
+        mSwipeEdge = swipeEdge;
+        mFrameTime = frameTime;
     }
 
     /**
@@ -115,13 +147,38 @@
         return mSwipeEdge;
     }
 
+    /**
+     * Returns the frameTime of the BackEvent in milliseconds. Useful for calculating velocity.
+     */
+    @FlaggedApi(FLAG_PREDICTIVE_BACK_TIMESTAMP_API)
+    public long getFrameTime() {
+        return mFrameTime;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof BackEvent)) {
+            return false;
+        }
+        final BackEvent that = (BackEvent) other;
+        return mTouchX == that.mTouchX
+                && mTouchY == that.mTouchY
+                && mProgress == that.mProgress
+                && mSwipeEdge == that.mSwipeEdge
+                && mFrameTime == that.mFrameTime;
+    }
+
     @Override
     public String toString() {
         return "BackEvent{"
                 + "mTouchX=" + mTouchX
                 + ", mTouchY=" + mTouchY
                 + ", mProgress=" + mProgress
-                + ", mSwipeEdge" + mSwipeEdge
+                + ", mSwipeEdge=" + mSwipeEdge
+                + ", mFrameTime=" + mFrameTime + "ms"
                 + "}";
     }
 }
diff --git a/core/java/android/window/BackMotionEvent.java b/core/java/android/window/BackMotionEvent.java
index 8ac68ab..a8ec4ee 100644
--- a/core/java/android/window/BackMotionEvent.java
+++ b/core/java/android/window/BackMotionEvent.java
@@ -33,6 +33,7 @@
 public final class BackMotionEvent implements Parcelable {
     private final float mTouchX;
     private final float mTouchY;
+    private final long mFrameTime;
     private final float mProgress;
     private final boolean mTriggerBack;
 
@@ -48,6 +49,7 @@
      *
      * @param touchX Absolute X location of the touch point of this event.
      * @param touchY Absolute Y location of the touch point of this event.
+     * @param frameTime Event time of the corresponding touch event.
      * @param progress Value between 0 and 1 on how far along the back gesture is.
      * @param triggerBack Indicates whether the back arrow is in the triggered state or not
      * @param swipeEdge Indicates which edge the swipe starts from.
@@ -57,12 +59,14 @@
     public BackMotionEvent(
             float touchX,
             float touchY,
+            long frameTime,
             float progress,
             boolean triggerBack,
             @BackEvent.SwipeEdge int swipeEdge,
             @Nullable RemoteAnimationTarget departingAnimationTarget) {
         mTouchX = touchX;
         mTouchY = touchY;
+        mFrameTime = frameTime;
         mProgress = progress;
         mTriggerBack = triggerBack;
         mSwipeEdge = swipeEdge;
@@ -76,6 +80,7 @@
         mTriggerBack = in.readBoolean();
         mSwipeEdge = in.readInt();
         mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
+        mFrameTime = in.readLong();
     }
 
     @NonNull
@@ -104,6 +109,7 @@
         dest.writeBoolean(mTriggerBack);
         dest.writeInt(mSwipeEdge);
         dest.writeTypedObject(mDepartingAnimationTarget, flags);
+        dest.writeLong(mFrameTime);
     }
 
     /**
@@ -148,6 +154,13 @@
     }
 
     /**
+     * Returns the frame time of the BackMotionEvent in milliseconds.
+     */
+    public long getFrameTime() {
+        return mFrameTime;
+    }
+
+    /**
      * Returns the {@link RemoteAnimationTarget} of the top departing application window,
      * or {@code null} if the top window should not be moved for the current type of back
      * destination.
@@ -162,10 +175,11 @@
         return "BackMotionEvent{"
                 + "mTouchX=" + mTouchX
                 + ", mTouchY=" + mTouchY
+                + ", mFrameTime=" + mFrameTime + "ms"
                 + ", mProgress=" + mProgress
                 + ", mTriggerBack=" + mTriggerBack
-                + ", mSwipeEdge" + mSwipeEdge
-                + ", mDepartingAnimationTarget" + mDepartingAnimationTarget
+                + ", mSwipeEdge=" + mSwipeEdge
+                + ", mDepartingAnimationTarget=" + mDepartingAnimationTarget
                 + "}";
     }
 }
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index 465e11a..a5be58b 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -17,6 +17,7 @@
 package android.window;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.window.flags.Flags.predictiveBackTimestampApi;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -66,7 +67,8 @@
                 reset();
             };
     private final DynamicAnimation.OnAnimationUpdateListener mOnBackInvokedFlingUpdateListener =
-            (animation, progress, velocity) -> updateProgressValue(progress, velocity);
+            (animation, progress, velocity) ->
+                    updateProgressValue(progress, velocity, animation.getLastFrameTime());
 
 
     private void setProgress(float progress) {
@@ -92,7 +94,9 @@
 
     @Override
     public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
-        if (mBackInvokedFinishRunnable == null) updateProgressValue(value, velocity);
+        if (mBackInvokedFinishRunnable == null) {
+            updateProgressValue(value, velocity, animation.getLastFrameTime());
+        }
     }
 
 
@@ -137,7 +141,9 @@
         mLastBackEvent = event;
         mCallback = callback;
         mBackAnimationInProgress = true;
-        updateProgressValue(0, 0);
+        updateProgressValue(/* progress */ 0, /* velocity */ 0,
+                /* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS);
+        onBackProgressed(event);
     }
 
     /**
@@ -146,7 +152,8 @@
     public void reset() {
         if (mBackCancelledFinishRunnable != null) {
             // Ensure that last progress value that apps see is 0
-            updateProgressValue(0, 0);
+            updateProgressValue(/* progress */ 0, /* velocity */ 0,
+                    /* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS);
             invokeBackCancelledRunnable();
         } else if (mBackInvokedFinishRunnable != null) {
             invokeBackInvokedRunnable();
@@ -236,14 +243,20 @@
         return mVelocity / SCALE_FACTOR;
     }
 
-    private void updateProgressValue(float progress, float velocity) {
+    private void updateProgressValue(float progress, float velocity, long frameTime) {
         mVelocity = velocity;
         if (mLastBackEvent == null || mCallback == null || !mBackAnimationInProgress) {
             return;
         }
-        mCallback.onProgressUpdate(
-                new BackEvent(mLastBackEvent.getTouchX(), mLastBackEvent.getTouchY(),
-                        progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge()));
+        BackEvent backEvent;
+        if (predictiveBackTimestampApi()) {
+            backEvent = new BackEvent(mLastBackEvent.getTouchX(), mLastBackEvent.getTouchY(),
+                    progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge(), frameTime);
+        } else {
+            backEvent = new BackEvent(mLastBackEvent.getTouchX(), mLastBackEvent.getTouchY(),
+                    progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge());
+        }
+        mCallback.onProgressUpdate(backEvent);
     }
 
     private void invokeBackCancelledRunnable() {
diff --git a/core/java/android/window/BackTouchTracker.java b/core/java/android/window/BackTouchTracker.java
index 290c494..39a3025 100644
--- a/core/java/android/window/BackTouchTracker.java
+++ b/core/java/android/window/BackTouchTracker.java
@@ -151,6 +151,7 @@
         return new BackMotionEvent(
                 /* touchX = */ mInitTouchX,
                 /* touchY = */ mInitTouchY,
+                /* frameTime = */ 0,
                 /* progress = */ 0,
                 /* triggerBack = */ mTriggerBack,
                 /* swipeEdge = */ mSwipeEdge,
@@ -235,6 +236,7 @@
         return new BackMotionEvent(
                 /* touchX = */ mLatestTouchX,
                 /* touchY = */ mLatestTouchY,
+                /* frameTime = */ 0,
                 /* progress = */ progress,
                 /* triggerBack = */ mTriggerBack,
                 /* swipeEdge = */ mSwipeEdge,
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index 66c35e2..8db1f95 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -17,6 +17,7 @@
 package android.window;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.window.flags.Flags.predictiveBackTimestampApi;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -235,8 +236,12 @@
         @Override
         public void onBackStarted(@NonNull BackEvent backEvent) {
             try {
+                long frameTime = 0;
+                if (predictiveBackTimestampApi()) {
+                    frameTime = backEvent.getFrameTime();
+                }
                 mIOnBackInvokedCallback.onBackStarted(
-                        new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(),
+                        new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(), frameTime,
                                 backEvent.getProgress(), false, backEvent.getSwipeEdge(),
                                 null));
             } catch (RemoteException e) {
@@ -247,8 +252,12 @@
         @Override
         public void onBackProgressed(@NonNull BackEvent backEvent) {
             try {
+                long frameTime = 0;
+                if (predictiveBackTimestampApi()) {
+                    frameTime = backEvent.getFrameTime();
+                }
                 mIOnBackInvokedCallback.onBackProgressed(
-                        new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(),
+                        new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(), frameTime,
                                 backEvent.getProgress(), false, backEvent.getSwipeEdge(),
                                 null));
             } catch (RemoteException e) {
diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java
index 5d14698..a68bdc0 100644
--- a/core/java/android/window/SurfaceSyncGroup.java
+++ b/core/java/android/window/SurfaceSyncGroup.java
@@ -839,6 +839,16 @@
     }
 
     /**
+     * Returns true if the SurfaceSyncGroup has completed its sync.
+     * @hide
+     */
+    public boolean isComplete() {
+        synchronized (mLock) {
+            return mFinished;
+        }
+    }
+
+    /**
      * A frame callback that is used to synchronize SurfaceViews. The owner of the SurfaceView must
      * implement onFrameStarted when trying to sync the SurfaceView. This is to ensure the sync
      * knows when the frame is ready to add to the sync.
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index 20d1b3b..a37bef8 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -83,13 +83,16 @@
     public static final int REFERENCE_CACHE = 1 << 1;
     /** This snapshot object is being persistent. */
     public static final int REFERENCE_PERSIST = 1 << 2;
+    /** This snapshot object is being used for content suggestion. */
+    public static final int REFERENCE_CONTENT_SUGGESTION = 1 << 3;
     @IntDef(flag = true, prefix = { "REFERENCE_" }, value = {
             REFERENCE_BROADCAST,
             REFERENCE_CACHE,
-            REFERENCE_PERSIST
+            REFERENCE_PERSIST,
+            REFERENCE_CONTENT_SUGGESTION
     })
     @Retention(RetentionPolicy.SOURCE)
-    @interface ReferenceFlags {}
+    public @interface ReferenceFlags {}
 
     public TaskSnapshot(long id, long captureTime,
             @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot,
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 8e495ec..34abf31 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -525,6 +525,22 @@
     }
 
     /**
+     * Disables or enables activities to be started in adjacent tasks (see
+     * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT}) for the specified root of any child tasks.  This
+     * differs from {@link #setLaunchAdjacentFlagRoot(WindowContainerToken)} which controls the
+     * preferred launch-adjacent target and allows for selectively setting which root tasks can
+     * support launch-adjacent.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setDisableLaunchAdjacent(
+            @NonNull WindowContainerToken container, boolean disabled) {
+        mHierarchyOps.add(HierarchyOp.createForSetDisableLaunchAdjacent(container.asBinder(),
+                disabled));
+        return this;
+    }
+
+    /**
      * Starts a task by id. The task is expected to already exist (eg. as a recent task).
      * @param taskId Id of task to start.
      * @param options bundle containing ActivityOptions for the task's top activity.
@@ -1488,6 +1504,7 @@
         public static final int HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION = 20;
         public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21;
         public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22;
+        public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1556,6 +1573,8 @@
 
         private @InsetsType int mExcludeInsetsTypes;
 
+        private boolean mLaunchAdjacentDisabled;
+
         public static HierarchyOp createForReparent(
                 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
@@ -1644,6 +1663,15 @@
                     .build();
         }
 
+        /** Create a hierarchy op for disabling launch adjacent. */
+        public static HierarchyOp createForSetDisableLaunchAdjacent(IBinder container,
+                boolean disabled) {
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT)
+                    .setContainer(container)
+                    .setLaunchAdjacentDisabled(disabled)
+                    .build();
+        }
+
         /** create a hierarchy op for deleting a task **/
         public static HierarchyOp createForRemoveTask(@NonNull IBinder container) {
             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK)
@@ -1695,6 +1723,7 @@
             mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch;
             mIsTrimmableFromRecents = copy.mIsTrimmableFromRecents;
             mExcludeInsetsTypes = copy.mExcludeInsetsTypes;
+            mLaunchAdjacentDisabled = copy.mLaunchAdjacentDisabled;
         }
 
         protected HierarchyOp(Parcel in) {
@@ -1719,6 +1748,7 @@
             mReparentLeafTaskIfRelaunch = in.readBoolean();
             mIsTrimmableFromRecents = in.readBoolean();
             mExcludeInsetsTypes = in.readInt();
+            mLaunchAdjacentDisabled = in.readBoolean();
         }
 
         public int getType() {
@@ -1814,13 +1844,11 @@
         }
 
         /** Denotes whether the parents should also be included in the op. */
-        @NonNull
         public boolean includingParents() {
             return mIncludingParents;
         }
 
-        /** Set the task to be trimmable */
-        @NonNull
+        /** Denotes whether the task can be trimmable from recents */
         public boolean isTrimmableFromRecents() {
             return mIsTrimmableFromRecents;
         }
@@ -1829,6 +1857,11 @@
             return mExcludeInsetsTypes;
         }
 
+        /** Denotes whether launch-adjacent flag is respected from this task or its children */
+        public boolean isLaunchAdjacentDisabled() {
+            return mLaunchAdjacentDisabled;
+        }
+
         /** Gets a string representation of a hierarchy-op type. */
         public static String hopToString(int type) {
             switch (type) {
@@ -1839,6 +1872,8 @@
                 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "SetAdjacentRoot";
                 case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "LaunchTask";
                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "SetAdjacentFlagRoot";
+                case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
+                    return "SetDisableLaunchAdjacent";
                 case HIERARCHY_OP_TYPE_PENDING_INTENT: return "PendingIntent";
                 case HIERARCHY_OP_TYPE_START_SHORTCUT: return "StartShortcut";
                 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: return "addInsetsFrameProvider";
@@ -1891,6 +1926,10 @@
                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
                     sb.append("container=").append(mContainer).append(" clearRoot=").append(mToTop);
                     break;
+                case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
+                    sb.append("container=").append(mContainer).append(" disabled=")
+                            .append(mLaunchAdjacentDisabled);
+                    break;
                 case HIERARCHY_OP_TYPE_START_SHORTCUT:
                     sb.append("options=").append(mLaunchOptions)
                             .append(" info=").append(mShortcutInfo);
@@ -1971,6 +2010,7 @@
             dest.writeBoolean(mReparentLeafTaskIfRelaunch);
             dest.writeBoolean(mIsTrimmableFromRecents);
             dest.writeInt(mExcludeInsetsTypes);
+            dest.writeBoolean(mLaunchAdjacentDisabled);
         }
 
         @Override
@@ -2047,6 +2087,8 @@
 
             private @InsetsType int mExcludeInsetsTypes;
 
+            private boolean mLaunchAdjacentDisabled;
+
             Builder(int type) {
                 mType = type;
             }
@@ -2153,6 +2195,11 @@
                 return this;
             }
 
+            Builder setLaunchAdjacentDisabled(boolean disabled) {
+                mLaunchAdjacentDisabled = disabled;
+                return this;
+            }
+
             HierarchyOp build() {
                 final HierarchyOp hierarchyOp = new HierarchyOp(mType);
                 hierarchyOp.mContainer = mContainer;
@@ -2179,6 +2226,7 @@
                 hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
                 hierarchyOp.mIsTrimmableFromRecents = mIsTrimmableFromRecents;
                 hierarchyOp.mExcludeInsetsTypes = mExcludeInsetsTypes;
+                hierarchyOp.mLaunchAdjacentDisabled = mLaunchAdjacentDisabled;
 
                 return hierarchyOp;
             }
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 44a374f..c9d458f 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -17,6 +17,7 @@
 package android.window;
 
 import static com.android.window.flags.Flags.predictiveBackPrioritySystemNavigationObserver;
+import static com.android.window.flags.Flags.predictiveBackTimestampApi;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -563,7 +564,8 @@
                 }
                 OnBackAnimationCallback animationCallback = getBackAnimationCallback();
                 if (animationCallback != null
-                        && !(callback instanceof ImeBackAnimationController)) {
+                        && !(callback instanceof ImeBackAnimationController)
+                        && !predictiveBackTimestampApi()) {
                     mProgressAnimator.onBackInvoked(() -> {
                         if (mIsSystemCallback) {
                             mSystemNavigationObserverCallbackRunnable.run();
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index f739622..235ba3a 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -37,6 +37,13 @@
 }
 
 flag {
+  name: "move_to_external_display_shortcut"
+  namespace: "large_screen_experiences_app_compat"
+  description: "Whether the move to external display shortcut in overview is available"
+  bug: "372872848"
+}
+
+flag {
   name: "app_compat_properties_api"
   is_exported: true
   namespace: "large_screen_experiences_app_compat"
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 155494f..1812953 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -239,6 +239,13 @@
 }
 
 flag {
+    name: "enable_desktop_windowing_enter_transitions"
+    namespace: "lse_desktop_experience"
+    description: "Enables enter desktop windowing transition & motion polish changes"
+    bug: "369763947"
+}
+
+flag {
     name: "enable_desktop_windowing_exit_transitions"
     namespace: "lse_desktop_experience"
     description: "Enables exit desktop windowing transition & motion polish changes"
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 622f8c8..0d235ff 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -70,17 +70,6 @@
 }
 
 flag {
-  name: "common_surface_animator"
-  namespace: "windowing_frontend"
-  description: "A reusable surface animator for default transition"
-  bug: "326331384"
-  is_fixed_read_only: true
-  metadata {
-    purpose: PURPOSE_BUGFIX
-  }
-}
-
-flag {
   name: "reduce_keyguard_transitions"
   namespace: "windowing_frontend"
   description: "Avoid setting keyguard transitions ready unless there are no other changes"
@@ -325,3 +314,11 @@
     is_fixed_read_only: true
     bug: "362938401"
 }
+
+flag {
+    name: "predictive_back_timestamp_api"
+    namespace: "systemui"
+    description: "expose timestamp in BackEvent (API extension)"
+    is_fixed_read_only: true
+    bug: "362938401"
+}
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 18c8eb4..de7ad34 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -1195,7 +1195,12 @@
 
         @Nullable
         protected Drawable loadIconFromResource(Resources res, int resId) {
-            return res.getDrawableForDensity(resId, mIconDpi);
+            try {
+                return res.getDrawableForDensity(resId, mIconDpi);
+            } catch (Resources.NotFoundException e) {
+                Log.e(TAG, "Resource not found", e);
+                return null;
+            }
         }
 
     }
diff --git a/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java b/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java
index d4fe7c8d..7a4c1a0 100644
--- a/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java
+++ b/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java
@@ -762,6 +762,10 @@
         return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance();
     }
 
+    public long getLastFrameTime() {
+        return mLastFrameTime;
+    }
+
     /****************Sub class animations**************/
     /**
      * Returns the acceleration at the given value with the given velocity.
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index f3dc896..a037cb4 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -218,6 +218,22 @@
         // NOTE: Registering that datasource is an async operation, so there may be no data traced
         // for some messages logged right after the construction of this class.
         mDataSource.register(params);
+
+        if (viewerConfigInputStreamProvider == null && viewerConfigFilePath != null) {
+            viewerConfigInputStreamProvider = new ViewerConfigInputStreamProvider() {
+                @NonNull
+                @Override
+                public ProtoInputStream getInputStream() {
+                    try {
+                        return new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
+                    } catch (FileNotFoundException e) {
+                        throw new RuntimeException(
+                                "Failed to load viewer config file " + viewerConfigFilePath, e);
+                    }
+                }
+            };
+        }
+
         this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
         this.mViewerConfigReader = viewerConfigReader;
         this.mCacheUpdater = cacheUpdater;
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index 0a80e00..3c201fc 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -39,7 +39,7 @@
      * or the viewer config is not loaded into memory.
      */
     @Nullable
-    public synchronized String getViewerString(long messageHash) {
+    public String getViewerString(long messageHash) {
         return mLogMessageMap.get(messageHash);
     }
 
@@ -179,6 +179,6 @@
             }
         }
 
-        throw new RuntimeException("Group " + group + "not found in viewer config");
+        throw new RuntimeException("Group " + group + " not found in viewer config");
     }
 }
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index 3e597d7..d3b1f97 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -20,16 +20,20 @@
 import android.annotation.Nullable;
 import android.app.Notification.ProgressStyle;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.graphics.drawable.LayerDrawable;
 import android.os.Bundle;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.RemotableViewMethod;
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
 
 import androidx.annotation.ColorInt;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.NotificationProgressDrawable.Part;
@@ -49,7 +53,13 @@
  */
 @RemoteViews.RemoteView
 public class NotificationProgressBar extends ProgressBar {
+    private static final String TAG = "NotificationProgressBar";
+
     private NotificationProgressModel mProgressModel;
+
+    @Nullable
+    private List<Part> mProgressDrawableParts = null;
+
     @Nullable
     private Drawable mProgressTrackerDrawable = null;
 
@@ -58,7 +68,7 @@
     }
 
     public NotificationProgressBar(Context context, AttributeSet attrs) {
-        this(context, attrs, com.android.internal.R.attr.progressBarStyle);
+        this(context, attrs, R.attr.progressBarStyle);
     }
 
     public NotificationProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -82,10 +92,42 @@
                 "Bundle shouldn't be null");
 
         mProgressModel = NotificationProgressModel.fromBundle(bundle);
+
+        if (mProgressModel.isIndeterminate()) {
+            final int indeterminateColor = mProgressModel.getIndeterminateColor();
+            setIndeterminateTintList(ColorStateList.valueOf(indeterminateColor));
+        } else {
+            mProgressDrawableParts = processAndConvertToDrawableParts(mProgressModel.getSegments(),
+                    mProgressModel.getPoints(),
+                    mProgressModel.getProgress(), mProgressModel.isStyledByProgress());
+
+            try {
+                final NotificationProgressDrawable drawable = getNotificationProgressDrawable();
+                drawable.setParts(mProgressDrawableParts);
+            } catch (IllegalStateException ex) {
+                Log.e(TAG, "Can't set parts because can't get NotificationProgressDrawable", ex);
+            }
+        }
     }
 
-    private void setProgressModel(@NonNull NotificationProgressModel model) {
-        mProgressModel = model;
+    @NonNull
+    private NotificationProgressDrawable getNotificationProgressDrawable() {
+        final Drawable d = getProgressDrawable();
+        if (d == null) {
+            throw new IllegalStateException("getProgressDrawable() returns null");
+        }
+        if (!(d instanceof LayerDrawable)) {
+            throw new IllegalStateException("getProgressDrawable() doesn't return a LayerDrawable");
+        }
+
+        final Drawable layer = ((LayerDrawable) d).findDrawableByLayerId(R.id.background);
+        if (!(layer instanceof NotificationProgressDrawable)) {
+            throw new IllegalStateException(
+                    "Couldn't get NotificationProgressDrawable, retrieved drawable is: " + (
+                            layer != null ? layer.toString() : null));
+        }
+
+        return (NotificationProgressDrawable) layer;
     }
 
     /**
@@ -97,7 +139,6 @@
     public void setProgressTrackerIcon(@Nullable Icon icon) {
     }
 
-
     /**
      * Async version of {@link #setProgressTrackerIcon}
      */
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
index 89ef875..2be7273 100644
--- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -45,6 +45,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -156,11 +157,18 @@
     }
 
     /**
-     *
+     * Set the segments and points that constitute the drawable.
+     */
+    public void setParts(List<Part> parts) {
+        mParts.clear();
+        mParts.addAll(parts);
+    }
+
+    /**
+     * Set the segments and points that constitute the drawable.
      */
     public void setParts(@NonNull Part... parts) {
-        mParts.clear();
-        mParts.addAll(Arrays.asList(parts));
+        setParts(Arrays.asList(parts));
     }
 
     @Override
@@ -379,7 +387,7 @@
         if (state.mThemeAttrsPoints != null) {
             final TypedArray a = t.resolveAttributes(
                     state.mThemeAttrsPoints, R.styleable.NotificationProgressDrawablePoints);
-            updateSegmentsFromTypedArray(a);
+            updatePointsFromTypedArray(a);
             a.recycle();
         }
     }
@@ -651,9 +659,11 @@
 
         State(@NonNull State orig, @Nullable Resources res) {
             mChangingConfigurations = orig.mChangingConfigurations;
+            mSegSegGap = orig.mSegSegGap;
+            mSegPointGap = orig.mSegPointGap;
+            mStrokeWidth = orig.mStrokeWidth;
             mStrokeColor = orig.mStrokeColor;
             mFadedStrokeColor = orig.mFadedStrokeColor;
-            mStrokeWidth = orig.mStrokeWidth;
             mStrokeDashWidth = orig.mStrokeDashWidth;
             mStrokeDashGap = orig.mStrokeDashGap;
             mPointRadius = orig.mPointRadius;
@@ -791,6 +801,7 @@
         final State state = mState;
 
         mStrokePaint.setStrokeWidth(state.mStrokeWidth);
+        mDashedStrokePaint.setStrokeWidth(state.mStrokeWidth);
 
         if (state.mStrokeDashWidth != 0.0f) {
             final DashPathEffect e = new DashPathEffect(
diff --git a/core/java/com/android/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java
index 98e6e85..adcc0f6 100644
--- a/core/java/com/android/internal/widget/NotificationRowIconView.java
+++ b/core/java/com/android/internal/widget/NotificationRowIconView.java
@@ -39,17 +39,24 @@
 
 /**
  * An image view that holds the icon displayed at the start of a notification row.
+ * This can generally either display the "small icon" of a notification set via
+ * {@link this#setImageIcon(Icon)}, or an app icon controlled and fetched by the provider set
+ * through {@link this#setIconProvider(NotificationIconProvider)}.
  */
 @RemoteViews.RemoteView
 public class NotificationRowIconView extends CachingIconView {
+    private NotificationIconProvider mIconProvider;
+
     private boolean mApplyCircularCrop = false;
     private boolean mShouldShowAppIcon = false;
+    private Drawable mAppIcon = null;
 
-    // Padding and background set on the view prior to being changed by setShouldShowAppIcon(true),
-    // to be restored if shouldShowAppIcon becomes false again.
+    // Padding, background and colors set on the view prior to being overridden when showing the app
+    // icon, to be restored if we're showing the small icon again.
     private Rect mOriginalPadding = null;
     private Drawable mOriginalBackground = null;
-
+    private int mOriginalBackgroundColor = ColoredIconHelper.COLOR_INVALID;
+    private int mOriginalIconColor = ColoredIconHelper.COLOR_INVALID;
 
     public NotificationRowIconView(Context context) {
         super(context);
@@ -81,6 +88,71 @@
         super.onFinishInflate();
     }
 
+    /**
+     * Sets the icon provider for this view. This is used to determine whether we should show the
+     * app icon instead of the small icon, and to fetch the app icon if needed.
+     */
+    public void setIconProvider(NotificationIconProvider iconProvider) {
+        mIconProvider = iconProvider;
+    }
+
+    private Drawable loadAppIcon() {
+        if (mIconProvider != null && mIconProvider.shouldShowAppIcon()) {
+            return mIconProvider.getAppIcon();
+        }
+        return null;
+    }
+
+    @RemotableViewMethod(asyncImpl = "setImageIconAsync")
+    @Override
+    public void setImageIcon(Icon icon) {
+        if (Flags.notificationsRedesignAppIcons()) {
+            if (mAppIcon != null) {
+                // We already know that we should be using the app icon, and we already loaded it.
+                // We assume that cannot change throughout the lifetime of a notification, so
+                // there's nothing to do here.
+                return;
+            }
+            mAppIcon = loadAppIcon();
+            if (mAppIcon != null) {
+                setImageDrawable(mAppIcon);
+                adjustViewForAppIcon();
+            } else {
+                super.setImageIcon(icon);
+                restoreViewForSmallIcon();
+            }
+            return;
+        }
+        super.setImageIcon(icon);
+    }
+
+    @RemotableViewMethod
+    @Override
+    public Runnable setImageIconAsync(Icon icon) {
+        if (Flags.notificationsRedesignAppIcons()) {
+            if (mAppIcon != null) {
+                // We already know that we should be using the app icon, and we already loaded it.
+                // We assume that cannot change throughout the lifetime of a notification, so
+                // there's nothing to do here.
+                return () -> {
+                };
+            }
+            mAppIcon = loadAppIcon();
+            if (mAppIcon != null) {
+                return () -> {
+                    setImageDrawable(mAppIcon);
+                    adjustViewForAppIcon();
+                };
+            } else {
+                return () -> {
+                    super.setImageIcon(icon);
+                    restoreViewForSmallIcon();
+                };
+            }
+        }
+        return super.setImageIconAsync(icon);
+    }
+
     /** Whether the icon represents the app icon (instead of the small icon). */
     @RemotableViewMethod
     public void setShouldShowAppIcon(boolean shouldShowAppIcon) {
@@ -91,35 +163,122 @@
 
             mShouldShowAppIcon = shouldShowAppIcon;
             if (mShouldShowAppIcon) {
-                if (mOriginalPadding == null && mOriginalBackground == null) {
-                    mOriginalPadding = new Rect(getPaddingLeft(), getPaddingTop(),
-                            getPaddingRight(), getPaddingBottom());
-                    mOriginalBackground = getBackground();
-                }
-
-                setPadding(0, 0, 0, 0);
-
-                // Make the background white in case the icon itself doesn't have one.
-                ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE,
-                        PorterDuff.Mode.SRC_ATOP);
-
-                if (mOriginalBackground == null) {
-                    setBackground(getContext().getDrawable(R.drawable.notification_icon_circle));
-                }
-                getBackground().mutate().setColorFilter(colorFilter);
+                adjustViewForAppIcon();
             } else {
                 // Restore original padding and background if needed
-                if (mOriginalPadding != null) {
-                    setPadding(mOriginalPadding.left, mOriginalPadding.top, mOriginalPadding.right,
-                            mOriginalPadding.bottom);
-                    mOriginalPadding = null;
-                }
-                setBackground(mOriginalBackground);
-                mOriginalBackground = null;
+                restoreViewForSmallIcon();
             }
         }
     }
 
+    /**
+     * Override padding and background from the view to display the app icon.
+     */
+    private void adjustViewForAppIcon() {
+        removePadding();
+
+        if (Flags.notificationsUseAppIconInRow()) {
+            addWhiteBackground();
+        } else {
+            // No need to set the background for notification redesign, since the icon
+            // factory already does that for us.
+            removeBackground();
+        }
+    }
+
+    /**
+     * Restore padding and background overridden by {@link this#adjustViewForAppIcon}.
+     * Does nothing if they were not overridden.
+     */
+    private void restoreViewForSmallIcon() {
+        restorePadding();
+        restoreBackground();
+        restoreColors();
+    }
+
+    private void removePadding() {
+        if (mOriginalPadding == null) {
+            mOriginalPadding = new Rect(getPaddingLeft(), getPaddingTop(),
+                    getPaddingRight(), getPaddingBottom());
+        }
+        setPadding(0, 0, 0, 0);
+    }
+
+    private void restorePadding() {
+        if (mOriginalPadding != null) {
+            setPadding(mOriginalPadding.left, mOriginalPadding.top,
+                    mOriginalPadding.right,
+                    mOriginalPadding.bottom);
+            mOriginalPadding = null;
+        }
+    }
+
+    private void removeBackground() {
+        if (mOriginalBackground == null) {
+            mOriginalBackground = getBackground();
+        }
+
+        setBackground(null);
+    }
+
+    private void addWhiteBackground() {
+        if (mOriginalBackground == null) {
+            mOriginalBackground = getBackground();
+        }
+
+        // Make the background white in case the icon itself doesn't have one.
+        ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE,
+                PorterDuff.Mode.SRC_ATOP);
+
+        if (mOriginalBackground == null) {
+            setBackground(getContext().getDrawable(R.drawable.notification_icon_circle));
+        }
+        getBackground().mutate().setColorFilter(colorFilter);
+    }
+
+    private void restoreBackground() {
+        // NOTE: This will not work if the original background was null, but that's better than
+        //  accidentally clearing the background. We expect that there's generally going to be one
+        //  anyway unless we manually clear it.
+        if (mOriginalBackground != null) {
+            setBackground(mOriginalBackground);
+            mOriginalBackground = null;
+        }
+    }
+
+    private void restoreColors() {
+        if (mOriginalBackgroundColor != ColoredIconHelper.COLOR_INVALID) {
+            super.setBackgroundColor(mOriginalBackgroundColor);
+            mOriginalBackgroundColor = ColoredIconHelper.COLOR_INVALID;
+        }
+        if (mOriginalIconColor != ColoredIconHelper.COLOR_INVALID) {
+            super.setOriginalIconColor(mOriginalIconColor);
+            mOriginalIconColor = ColoredIconHelper.COLOR_INVALID;
+        }
+    }
+
+    @RemotableViewMethod
+    @Override
+    public void setBackgroundColor(int color) {
+        // Ignore color overrides if we're showing the app icon.
+        if (mAppIcon == null) {
+            super.setBackgroundColor(color);
+        } else {
+            mOriginalBackgroundColor = color;
+        }
+    }
+
+    @RemotableViewMethod
+    @Override
+    public void setOriginalIconColor(int color) {
+        // Ignore color overrides if we're showing the app icon.
+        if (mAppIcon == null) {
+            super.setOriginalIconColor(color);
+        } else {
+            mOriginalIconColor = color;
+        }
+    }
+
     @Nullable
     @Override
     Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
@@ -197,4 +356,17 @@
 
         return bitmap;
     }
+
+    /**
+     * A provider that allows this view to verify whether it should use the app icon instead of the
+     * icon provided to it via setImageIcon, as well as actually fetching the app icon. It should
+     * primarily be called on the background thread.
+     */
+    public interface NotificationIconProvider {
+        /** Whether this notification should use the app icon instead of the small icon. */
+        boolean shouldShowAppIcon();
+
+        /** Get the app icon for this notification. */
+        Drawable getAppIcon();
+    }
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 9bccf5a..8eaa7aa 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -747,16 +747,12 @@
                                           indexMax));
 }
 
-static jint
-android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
-                                               jobject thiz,
-                                               jint stream,
-                                               jint index,
-                                               jint device)
-{
+static jint android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream,
+                                                           jint index, jboolean muted,
+                                                           jint device) {
     return check_AudioSystem_Command(
             AudioSystem::setStreamVolumeIndex(static_cast<audio_stream_type_t>(stream), index,
-                                              static_cast<audio_devices_t>(device)));
+                                              muted, static_cast<audio_devices_t>(device)));
 }
 
 static jint
@@ -773,13 +769,9 @@
     return index;
 }
 
-static jint
-android_media_AudioSystem_setVolumeIndexForAttributes(JNIEnv *env,
-                                                      jobject thiz,
-                                                      jobject jaa,
-                                                      jint index,
-                                                      jint device)
-{
+static jint android_media_AudioSystem_setVolumeIndexForAttributes(JNIEnv *env, jobject thiz,
+                                                                  jobject jaa, jint index,
+                                                                  jboolean muted, jint device) {
     // read the AudioAttributes values
     JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
     jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
@@ -787,7 +779,7 @@
         return jStatus;
     }
     return check_AudioSystem_Command(
-            AudioSystem::setVolumeIndexForAttributes(*(paa.get()), index,
+            AudioSystem::setVolumeIndexForAttributes(*(paa.get()), index, muted,
                                                      static_cast<audio_devices_t>(device)));
 }
 
@@ -3448,182 +3440,179 @@
 #define MAKE_AUDIO_SYSTEM_METHOD(x) \
     MAKE_JNI_NATIVE_METHOD_AUTOSIG(#x, android_media_AudioSystem_##x)
 
-static const JNINativeMethod gMethods[] =
-        {MAKE_AUDIO_SYSTEM_METHOD(setParameters),
-         MAKE_AUDIO_SYSTEM_METHOD(getParameters),
-         MAKE_AUDIO_SYSTEM_METHOD(muteMicrophone),
-         MAKE_AUDIO_SYSTEM_METHOD(isMicrophoneMuted),
-         MAKE_AUDIO_SYSTEM_METHOD(isStreamActive),
-         MAKE_AUDIO_SYSTEM_METHOD(isStreamActiveRemotely),
-         MAKE_AUDIO_SYSTEM_METHOD(isSourceActive),
-         MAKE_AUDIO_SYSTEM_METHOD(newAudioSessionId),
-         MAKE_AUDIO_SYSTEM_METHOD(newAudioPlayerId),
-         MAKE_AUDIO_SYSTEM_METHOD(newAudioRecorderId),
-         MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
-                                android_media_AudioSystem_setDeviceConnectionState),
-         MAKE_AUDIO_SYSTEM_METHOD(getDeviceConnectionState),
-         MAKE_AUDIO_SYSTEM_METHOD(handleDeviceConfigChange),
-         MAKE_AUDIO_SYSTEM_METHOD(setPhoneState),
-         MAKE_AUDIO_SYSTEM_METHOD(setForceUse),
-         MAKE_AUDIO_SYSTEM_METHOD(getForceUse),
-         MAKE_AUDIO_SYSTEM_METHOD(setDeviceAbsoluteVolumeEnabled),
-         MAKE_AUDIO_SYSTEM_METHOD(initStreamVolume),
-         MAKE_AUDIO_SYSTEM_METHOD(setStreamVolumeIndex),
-         MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeIndex),
-         MAKE_JNI_NATIVE_METHOD("setVolumeIndexForAttributes",
-                                "(Landroid/media/AudioAttributes;II)I",
-                                android_media_AudioSystem_setVolumeIndexForAttributes),
-         MAKE_JNI_NATIVE_METHOD("getVolumeIndexForAttributes",
-                                "(Landroid/media/AudioAttributes;I)I",
-                                android_media_AudioSystem_getVolumeIndexForAttributes),
-         MAKE_JNI_NATIVE_METHOD("getMinVolumeIndexForAttributes",
-                                "(Landroid/media/AudioAttributes;)I",
-                                android_media_AudioSystem_getMinVolumeIndexForAttributes),
-         MAKE_JNI_NATIVE_METHOD("getMaxVolumeIndexForAttributes",
-                                "(Landroid/media/AudioAttributes;)I",
-                                android_media_AudioSystem_getMaxVolumeIndexForAttributes),
-         MAKE_AUDIO_SYSTEM_METHOD(setMasterVolume),
-         MAKE_AUDIO_SYSTEM_METHOD(getMasterVolume),
-         MAKE_AUDIO_SYSTEM_METHOD(setMasterMute),
-         MAKE_AUDIO_SYSTEM_METHOD(getMasterMute),
-         MAKE_AUDIO_SYSTEM_METHOD(setMasterMono),
-         MAKE_AUDIO_SYSTEM_METHOD(getMasterMono),
-         MAKE_AUDIO_SYSTEM_METHOD(setMasterBalance),
-         MAKE_AUDIO_SYSTEM_METHOD(getMasterBalance),
-         MAKE_AUDIO_SYSTEM_METHOD(getPrimaryOutputSamplingRate),
-         MAKE_AUDIO_SYSTEM_METHOD(getPrimaryOutputFrameCount),
-         MAKE_AUDIO_SYSTEM_METHOD(getOutputLatency),
-         MAKE_AUDIO_SYSTEM_METHOD(setLowRamDevice),
-         MAKE_AUDIO_SYSTEM_METHOD(checkAudioFlinger),
-         MAKE_JNI_NATIVE_METHOD("setAudioFlingerBinder", "(Landroid/os/IBinder;)V",
-                                android_media_AudioSystem_setAudioFlingerBinder),
-         MAKE_JNI_NATIVE_METHOD("listAudioPorts", "(Ljava/util/ArrayList;[I)I",
-                                android_media_AudioSystem_listAudioPorts),
-         MAKE_JNI_NATIVE_METHOD("getSupportedDeviceTypes", "(ILandroid/util/IntArray;)I",
-                                android_media_AudioSystem_getSupportedDeviceTypes),
-         MAKE_JNI_NATIVE_METHOD("createAudioPatch",
-                                "([Landroid/media/AudioPatch;[Landroid/media/"
-                                "AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
-                                android_media_AudioSystem_createAudioPatch),
-         MAKE_JNI_NATIVE_METHOD("releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
-                                android_media_AudioSystem_releaseAudioPatch),
-         MAKE_JNI_NATIVE_METHOD("listAudioPatches", "(Ljava/util/ArrayList;[I)I",
-                                android_media_AudioSystem_listAudioPatches),
-         MAKE_JNI_NATIVE_METHOD("setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
-                                android_media_AudioSystem_setAudioPortConfig),
-         MAKE_JNI_NATIVE_METHOD("startAudioSource",
-                                "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
-                                android_media_AudioSystem_startAudioSource),
-         MAKE_AUDIO_SYSTEM_METHOD(stopAudioSource),
-         MAKE_AUDIO_SYSTEM_METHOD(getAudioHwSyncForSession),
-         MAKE_JNI_NATIVE_METHOD("registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
-                                android_media_AudioSystem_registerPolicyMixes),
-         MAKE_JNI_NATIVE_METHOD("getRegisteredPolicyMixes", "(Ljava/util/List;)I",
-                                android_media_AudioSystem_getRegisteredPolicyMixes),
-         MAKE_JNI_NATIVE_METHOD("updatePolicyMixes",
-                                "([Landroid/media/audiopolicy/AudioMix;[Landroid/media/audiopolicy/"
-                                "AudioMixingRule;)I",
-                                android_media_AudioSystem_updatePolicyMixes),
-         MAKE_JNI_NATIVE_METHOD("setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_setUidDeviceAffinities),
-         MAKE_AUDIO_SYSTEM_METHOD(removeUidDeviceAffinities),
-         MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_dynamic_policy_callback",
-                                        android_media_AudioSystem_registerDynPolicyCallback),
-         MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_recording_callback",
-                                        android_media_AudioSystem_registerRecordingCallback),
-         MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_routing_callback",
-                                        android_media_AudioSystem_registerRoutingCallback),
-         MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_vol_range_init_req_callback",
-                                        android_media_AudioSystem_registerVolRangeInitReqCallback),
-         MAKE_AUDIO_SYSTEM_METHOD(systemReady),
-         MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeDB),
-         MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_get_offload_support",
-                                        android_media_AudioSystem_getOffloadSupport),
-         MAKE_JNI_NATIVE_METHOD("getMicrophones", "(Ljava/util/ArrayList;)I",
-                                android_media_AudioSystem_getMicrophones),
-         MAKE_JNI_NATIVE_METHOD("getSurroundFormats", "(Ljava/util/Map;)I",
-                                android_media_AudioSystem_getSurroundFormats),
-         MAKE_JNI_NATIVE_METHOD("getReportedSurroundFormats", "(Ljava/util/ArrayList;)I",
-                                android_media_AudioSystem_getReportedSurroundFormats),
-         MAKE_AUDIO_SYSTEM_METHOD(setSurroundFormatEnabled),
-         MAKE_AUDIO_SYSTEM_METHOD(setAssistantServicesUids),
-         MAKE_AUDIO_SYSTEM_METHOD(setActiveAssistantServicesUids),
-         MAKE_AUDIO_SYSTEM_METHOD(setA11yServicesUids),
-         MAKE_AUDIO_SYSTEM_METHOD(isHapticPlaybackSupported),
-         MAKE_AUDIO_SYSTEM_METHOD(isUltrasoundSupported),
-         MAKE_JNI_NATIVE_METHOD(
-                 "getHwOffloadFormatsSupportedForBluetoothMedia", "(ILjava/util/ArrayList;)I",
-                 android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia),
-         MAKE_AUDIO_SYSTEM_METHOD(setSupportedSystemUsages),
-         MAKE_AUDIO_SYSTEM_METHOD(setAllowedCapturePolicy),
-         MAKE_AUDIO_SYSTEM_METHOD(setRttEnabled),
-         MAKE_AUDIO_SYSTEM_METHOD(setAudioHalPids),
-         MAKE_AUDIO_SYSTEM_METHOD(isCallScreeningModeSupported),
-         MAKE_JNI_NATIVE_METHOD("setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_setDevicesRoleForStrategy),
-         MAKE_JNI_NATIVE_METHOD("removeDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_removeDevicesRoleForStrategy),
-         MAKE_AUDIO_SYSTEM_METHOD(clearDevicesRoleForStrategy),
-         MAKE_JNI_NATIVE_METHOD("getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
-                                android_media_AudioSystem_getDevicesForRoleAndStrategy),
-         MAKE_JNI_NATIVE_METHOD("setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_setDevicesRoleForCapturePreset),
-         MAKE_JNI_NATIVE_METHOD("addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_addDevicesRoleForCapturePreset),
-         MAKE_JNI_NATIVE_METHOD("removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_removeDevicesRoleForCapturePreset),
-         MAKE_AUDIO_SYSTEM_METHOD(clearDevicesRoleForCapturePreset),
-         MAKE_JNI_NATIVE_METHOD("getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
-                                android_media_AudioSystem_getDevicesForRoleAndCapturePreset),
-         MAKE_JNI_NATIVE_METHOD("getDevicesForAttributes",
-                                "(Landroid/media/AudioAttributes;[Landroid/media/"
-                                "AudioDeviceAttributes;Z)I",
-                                android_media_AudioSystem_getDevicesForAttributes),
-         MAKE_JNI_NATIVE_METHOD("setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I",
-                                android_media_AudioSystem_setUserIdDeviceAffinities),
-         MAKE_AUDIO_SYSTEM_METHOD(removeUserIdDeviceAffinities),
-         MAKE_AUDIO_SYSTEM_METHOD(setCurrentImeUid),
-         MAKE_JNI_NATIVE_METHOD("setVibratorInfos", "(Ljava/util/List;)I",
-                                android_media_AudioSystem_setVibratorInfos),
-         MAKE_JNI_NATIVE_METHOD("nativeGetSpatializer",
-                                "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
-                                android_media_AudioSystem_getSpatializer),
-         MAKE_JNI_NATIVE_METHOD("canBeSpatialized",
-                                "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
-                                "[Landroid/media/AudioDeviceAttributes;)Z",
-                                android_media_AudioSystem_canBeSpatialized),
-         MAKE_JNI_NATIVE_METHOD("nativeGetSoundDose",
-                                "(Landroid/media/ISoundDoseCallback;)Landroid/os/IBinder;",
-                                android_media_AudioSystem_nativeGetSoundDose),
-         MAKE_JNI_NATIVE_METHOD("getDirectPlaybackSupport",
-                                "(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
-                                android_media_AudioSystem_getDirectPlaybackSupport),
-         MAKE_JNI_NATIVE_METHOD("getDirectProfilesForAttributes",
-                                "(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
-                                android_media_AudioSystem_getDirectProfilesForAttributes),
-         MAKE_JNI_NATIVE_METHOD("getSupportedMixerAttributes", "(ILjava/util/List;)I",
-                                android_media_AudioSystem_getSupportedMixerAttributes),
-         MAKE_JNI_NATIVE_METHOD("setPreferredMixerAttributes",
-                                "(Landroid/media/AudioAttributes;IILandroid/media/"
-                                "AudioMixerAttributes;)I",
-                                android_media_AudioSystem_setPreferredMixerAttributes),
-         MAKE_JNI_NATIVE_METHOD("getPreferredMixerAttributes",
-                                "(Landroid/media/AudioAttributes;ILjava/util/List;)I",
-                                android_media_AudioSystem_getPreferredMixerAttributes),
-         MAKE_JNI_NATIVE_METHOD("clearPreferredMixerAttributes",
-                                "(Landroid/media/AudioAttributes;II)I",
-                                android_media_AudioSystem_clearPreferredMixerAttributes),
-         MAKE_AUDIO_SYSTEM_METHOD(supportsBluetoothVariableLatency),
-         MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled),
-         MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled),
-         MAKE_JNI_NATIVE_METHOD("listenForSystemPropertyChange",
-                                "(Ljava/lang/String;Ljava/lang/Runnable;)J",
-                                android_media_AudioSystem_listenForSystemPropertyChange),
-         MAKE_JNI_NATIVE_METHOD("triggerSystemPropertyUpdate",
-                                "(J)V",
-                                android_media_AudioSystem_triggerSystemPropertyUpdate),
-
-        };
+static const JNINativeMethod gMethods[] = {
+        MAKE_AUDIO_SYSTEM_METHOD(setParameters),
+        MAKE_AUDIO_SYSTEM_METHOD(getParameters),
+        MAKE_AUDIO_SYSTEM_METHOD(muteMicrophone),
+        MAKE_AUDIO_SYSTEM_METHOD(isMicrophoneMuted),
+        MAKE_AUDIO_SYSTEM_METHOD(isStreamActive),
+        MAKE_AUDIO_SYSTEM_METHOD(isStreamActiveRemotely),
+        MAKE_AUDIO_SYSTEM_METHOD(isSourceActive),
+        MAKE_AUDIO_SYSTEM_METHOD(newAudioSessionId),
+        MAKE_AUDIO_SYSTEM_METHOD(newAudioPlayerId),
+        MAKE_AUDIO_SYSTEM_METHOD(newAudioRecorderId),
+        MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
+                               android_media_AudioSystem_setDeviceConnectionState),
+        MAKE_AUDIO_SYSTEM_METHOD(getDeviceConnectionState),
+        MAKE_AUDIO_SYSTEM_METHOD(handleDeviceConfigChange),
+        MAKE_AUDIO_SYSTEM_METHOD(setPhoneState),
+        MAKE_AUDIO_SYSTEM_METHOD(setForceUse),
+        MAKE_AUDIO_SYSTEM_METHOD(getForceUse),
+        MAKE_AUDIO_SYSTEM_METHOD(setDeviceAbsoluteVolumeEnabled),
+        MAKE_AUDIO_SYSTEM_METHOD(initStreamVolume),
+        MAKE_AUDIO_SYSTEM_METHOD(setStreamVolumeIndex),
+        MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeIndex),
+        MAKE_JNI_NATIVE_METHOD("setVolumeIndexForAttributes",
+                               "(Landroid/media/AudioAttributes;IZI)I",
+                               android_media_AudioSystem_setVolumeIndexForAttributes),
+        MAKE_JNI_NATIVE_METHOD("getVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;I)I",
+                               android_media_AudioSystem_getVolumeIndexForAttributes),
+        MAKE_JNI_NATIVE_METHOD("getMinVolumeIndexForAttributes",
+                               "(Landroid/media/AudioAttributes;)I",
+                               android_media_AudioSystem_getMinVolumeIndexForAttributes),
+        MAKE_JNI_NATIVE_METHOD("getMaxVolumeIndexForAttributes",
+                               "(Landroid/media/AudioAttributes;)I",
+                               android_media_AudioSystem_getMaxVolumeIndexForAttributes),
+        MAKE_AUDIO_SYSTEM_METHOD(setMasterVolume),
+        MAKE_AUDIO_SYSTEM_METHOD(getMasterVolume),
+        MAKE_AUDIO_SYSTEM_METHOD(setMasterMute),
+        MAKE_AUDIO_SYSTEM_METHOD(getMasterMute),
+        MAKE_AUDIO_SYSTEM_METHOD(setMasterMono),
+        MAKE_AUDIO_SYSTEM_METHOD(getMasterMono),
+        MAKE_AUDIO_SYSTEM_METHOD(setMasterBalance),
+        MAKE_AUDIO_SYSTEM_METHOD(getMasterBalance),
+        MAKE_AUDIO_SYSTEM_METHOD(getPrimaryOutputSamplingRate),
+        MAKE_AUDIO_SYSTEM_METHOD(getPrimaryOutputFrameCount),
+        MAKE_AUDIO_SYSTEM_METHOD(getOutputLatency),
+        MAKE_AUDIO_SYSTEM_METHOD(setLowRamDevice),
+        MAKE_AUDIO_SYSTEM_METHOD(checkAudioFlinger),
+        MAKE_JNI_NATIVE_METHOD("setAudioFlingerBinder", "(Landroid/os/IBinder;)V",
+                               android_media_AudioSystem_setAudioFlingerBinder),
+        MAKE_JNI_NATIVE_METHOD("listAudioPorts", "(Ljava/util/ArrayList;[I)I",
+                               android_media_AudioSystem_listAudioPorts),
+        MAKE_JNI_NATIVE_METHOD("getSupportedDeviceTypes", "(ILandroid/util/IntArray;)I",
+                               android_media_AudioSystem_getSupportedDeviceTypes),
+        MAKE_JNI_NATIVE_METHOD("createAudioPatch",
+                               "([Landroid/media/AudioPatch;[Landroid/media/"
+                               "AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
+                               android_media_AudioSystem_createAudioPatch),
+        MAKE_JNI_NATIVE_METHOD("releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
+                               android_media_AudioSystem_releaseAudioPatch),
+        MAKE_JNI_NATIVE_METHOD("listAudioPatches", "(Ljava/util/ArrayList;[I)I",
+                               android_media_AudioSystem_listAudioPatches),
+        MAKE_JNI_NATIVE_METHOD("setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
+                               android_media_AudioSystem_setAudioPortConfig),
+        MAKE_JNI_NATIVE_METHOD("startAudioSource",
+                               "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
+                               android_media_AudioSystem_startAudioSource),
+        MAKE_AUDIO_SYSTEM_METHOD(stopAudioSource),
+        MAKE_AUDIO_SYSTEM_METHOD(getAudioHwSyncForSession),
+        MAKE_JNI_NATIVE_METHOD("registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
+                               android_media_AudioSystem_registerPolicyMixes),
+        MAKE_JNI_NATIVE_METHOD("getRegisteredPolicyMixes", "(Ljava/util/List;)I",
+                               android_media_AudioSystem_getRegisteredPolicyMixes),
+        MAKE_JNI_NATIVE_METHOD("updatePolicyMixes",
+                               "([Landroid/media/audiopolicy/AudioMix;[Landroid/media/audiopolicy/"
+                               "AudioMixingRule;)I",
+                               android_media_AudioSystem_updatePolicyMixes),
+        MAKE_JNI_NATIVE_METHOD("setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_setUidDeviceAffinities),
+        MAKE_AUDIO_SYSTEM_METHOD(removeUidDeviceAffinities),
+        MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_dynamic_policy_callback",
+                                       android_media_AudioSystem_registerDynPolicyCallback),
+        MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_recording_callback",
+                                       android_media_AudioSystem_registerRecordingCallback),
+        MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_routing_callback",
+                                       android_media_AudioSystem_registerRoutingCallback),
+        MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_vol_range_init_req_callback",
+                                       android_media_AudioSystem_registerVolRangeInitReqCallback),
+        MAKE_AUDIO_SYSTEM_METHOD(systemReady),
+        MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeDB),
+        MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_get_offload_support",
+                                       android_media_AudioSystem_getOffloadSupport),
+        MAKE_JNI_NATIVE_METHOD("getMicrophones", "(Ljava/util/ArrayList;)I",
+                               android_media_AudioSystem_getMicrophones),
+        MAKE_JNI_NATIVE_METHOD("getSurroundFormats", "(Ljava/util/Map;)I",
+                               android_media_AudioSystem_getSurroundFormats),
+        MAKE_JNI_NATIVE_METHOD("getReportedSurroundFormats", "(Ljava/util/ArrayList;)I",
+                               android_media_AudioSystem_getReportedSurroundFormats),
+        MAKE_AUDIO_SYSTEM_METHOD(setSurroundFormatEnabled),
+        MAKE_AUDIO_SYSTEM_METHOD(setAssistantServicesUids),
+        MAKE_AUDIO_SYSTEM_METHOD(setActiveAssistantServicesUids),
+        MAKE_AUDIO_SYSTEM_METHOD(setA11yServicesUids),
+        MAKE_AUDIO_SYSTEM_METHOD(isHapticPlaybackSupported),
+        MAKE_AUDIO_SYSTEM_METHOD(isUltrasoundSupported),
+        MAKE_JNI_NATIVE_METHOD(
+                "getHwOffloadFormatsSupportedForBluetoothMedia", "(ILjava/util/ArrayList;)I",
+                android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia),
+        MAKE_AUDIO_SYSTEM_METHOD(setSupportedSystemUsages),
+        MAKE_AUDIO_SYSTEM_METHOD(setAllowedCapturePolicy),
+        MAKE_AUDIO_SYSTEM_METHOD(setRttEnabled),
+        MAKE_AUDIO_SYSTEM_METHOD(setAudioHalPids),
+        MAKE_AUDIO_SYSTEM_METHOD(isCallScreeningModeSupported),
+        MAKE_JNI_NATIVE_METHOD("setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_setDevicesRoleForStrategy),
+        MAKE_JNI_NATIVE_METHOD("removeDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_removeDevicesRoleForStrategy),
+        MAKE_AUDIO_SYSTEM_METHOD(clearDevicesRoleForStrategy),
+        MAKE_JNI_NATIVE_METHOD("getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
+                               android_media_AudioSystem_getDevicesForRoleAndStrategy),
+        MAKE_JNI_NATIVE_METHOD("setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_setDevicesRoleForCapturePreset),
+        MAKE_JNI_NATIVE_METHOD("addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_addDevicesRoleForCapturePreset),
+        MAKE_JNI_NATIVE_METHOD("removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_removeDevicesRoleForCapturePreset),
+        MAKE_AUDIO_SYSTEM_METHOD(clearDevicesRoleForCapturePreset),
+        MAKE_JNI_NATIVE_METHOD("getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
+                               android_media_AudioSystem_getDevicesForRoleAndCapturePreset),
+        MAKE_JNI_NATIVE_METHOD("getDevicesForAttributes",
+                               "(Landroid/media/AudioAttributes;[Landroid/media/"
+                               "AudioDeviceAttributes;Z)I",
+                               android_media_AudioSystem_getDevicesForAttributes),
+        MAKE_JNI_NATIVE_METHOD("setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+                               android_media_AudioSystem_setUserIdDeviceAffinities),
+        MAKE_AUDIO_SYSTEM_METHOD(removeUserIdDeviceAffinities),
+        MAKE_AUDIO_SYSTEM_METHOD(setCurrentImeUid),
+        MAKE_JNI_NATIVE_METHOD("setVibratorInfos", "(Ljava/util/List;)I",
+                               android_media_AudioSystem_setVibratorInfos),
+        MAKE_JNI_NATIVE_METHOD("nativeGetSpatializer",
+                               "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
+                               android_media_AudioSystem_getSpatializer),
+        MAKE_JNI_NATIVE_METHOD("canBeSpatialized",
+                               "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
+                               "[Landroid/media/AudioDeviceAttributes;)Z",
+                               android_media_AudioSystem_canBeSpatialized),
+        MAKE_JNI_NATIVE_METHOD("nativeGetSoundDose",
+                               "(Landroid/media/ISoundDoseCallback;)Landroid/os/IBinder;",
+                               android_media_AudioSystem_nativeGetSoundDose),
+        MAKE_JNI_NATIVE_METHOD("getDirectPlaybackSupport",
+                               "(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
+                               android_media_AudioSystem_getDirectPlaybackSupport),
+        MAKE_JNI_NATIVE_METHOD("getDirectProfilesForAttributes",
+                               "(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
+                               android_media_AudioSystem_getDirectProfilesForAttributes),
+        MAKE_JNI_NATIVE_METHOD("getSupportedMixerAttributes", "(ILjava/util/List;)I",
+                               android_media_AudioSystem_getSupportedMixerAttributes),
+        MAKE_JNI_NATIVE_METHOD("setPreferredMixerAttributes",
+                               "(Landroid/media/AudioAttributes;IILandroid/media/"
+                               "AudioMixerAttributes;)I",
+                               android_media_AudioSystem_setPreferredMixerAttributes),
+        MAKE_JNI_NATIVE_METHOD("getPreferredMixerAttributes",
+                               "(Landroid/media/AudioAttributes;ILjava/util/List;)I",
+                               android_media_AudioSystem_getPreferredMixerAttributes),
+        MAKE_JNI_NATIVE_METHOD("clearPreferredMixerAttributes",
+                               "(Landroid/media/AudioAttributes;II)I",
+                               android_media_AudioSystem_clearPreferredMixerAttributes),
+        MAKE_AUDIO_SYSTEM_METHOD(supportsBluetoothVariableLatency),
+        MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled),
+        MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled),
+        MAKE_JNI_NATIVE_METHOD("listenForSystemPropertyChange",
+                               "(Ljava/lang/String;Ljava/lang/Runnable;)J",
+                               android_media_AudioSystem_listenForSystemPropertyChange),
+        MAKE_JNI_NATIVE_METHOD("triggerSystemPropertyUpdate", "(J)V",
+                               android_media_AudioSystem_triggerSystemPropertyUpdate),
+};
 
 static const JNINativeMethod gEventHandlerMethods[] =
         {MAKE_JNI_NATIVE_METHOD("native_setup", "(Ljava/lang/Object;)V",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a939d92..755704a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -115,6 +115,7 @@
     jfieldID supportedDisplayModes;
     jfieldID activeDisplayModeId;
     jfieldID renderFrameRate;
+    jfieldID hasArrSupport;
     jfieldID supportedColorModes;
     jfieldID activeColorMode;
     jfieldID hdrCapabilities;
@@ -1453,7 +1454,7 @@
     env->SetIntField(object, gDynamicDisplayInfoClassInfo.activeDisplayModeId,
                      info.activeDisplayModeId);
     env->SetFloatField(object, gDynamicDisplayInfoClassInfo.renderFrameRate, info.renderFrameRate);
-
+    env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.hasArrSupport, info.hasArrSupport);
     jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size());
     if (colorModesArray == NULL) {
         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
@@ -2641,6 +2642,8 @@
             GetFieldIDOrDie(env, dynamicInfoClazz, "activeDisplayModeId", "I");
     gDynamicDisplayInfoClassInfo.renderFrameRate =
             GetFieldIDOrDie(env, dynamicInfoClazz, "renderFrameRate", "F");
+    gDynamicDisplayInfoClassInfo.hasArrSupport =
+            GetFieldIDOrDie(env, dynamicInfoClazz, "hasArrSupport", "Z");
     gDynamicDisplayInfoClassInfo.supportedColorModes =
             GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I");
     gDynamicDisplayInfoClassInfo.activeColorMode =
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 06621c9..bd403c7 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -262,7 +262,8 @@
 }
 
 // returns result from java.lang.System.getProperty
-static string getJavaProperty(JNIEnv* env, const char* property_name) {
+static string getJavaProperty(JNIEnv* env, const char* property_name,
+                              const char* defaultValue = "") {
     jclass system = FindClassOrDie(env, "java/lang/System");
     jmethodID getPropertyMethod =
             GetStaticMethodIDOrDie(env, system, "getProperty",
@@ -270,7 +271,7 @@
 
     auto jString = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
                                                         env->NewStringUTF(property_name),
-                                                        env->NewStringUTF(""));
+                                                        env->NewStringUTF(defaultValue));
     ScopedUtfChars chars(env, jString);
     return string(chars.c_str());
 }
@@ -430,7 +431,6 @@
 
 } // namespace android
 
-#ifndef _WIN32
 using namespace android;
 
 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
@@ -439,12 +439,14 @@
         return JNI_ERR;
     }
 
-    Vector<String8> args;
-    HostRuntime runtime;
+    string useBaseHostRuntime = getJavaProperty(env, "use_base_native_hostruntime", "true");
+    if (useBaseHostRuntime == "true") {
+        Vector<String8> args;
+        HostRuntime runtime;
 
-    runtime.onVmCreated(env);
-    runtime.start("HostRuntime", args, false);
+        runtime.onVmCreated(env);
+        runtime.start("HostRuntime", args, false);
+    }
 
     return JNI_VERSION_1_6;
 }
-#endif
diff --git a/core/res/res/drawable/ic_zen_mode_icon_piano.xml b/core/res/res/drawable/ic_zen_mode_icon_piano.xml
new file mode 100644
index 0000000..012b939
--- /dev/null
+++ b/core/res/res/drawable/ic_zen_mode_icon_piano.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L330,760L330,580L320,580Q303,580 291.5,568.5Q280,557 280,540L280,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760ZM630,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L680,200L680,540Q680,557 668.5,568.5Q657,580 640,580L630,580L630,760ZM390,760L570,760L570,580L560,580Q543,580 531.5,568.5Q520,557 520,540L520,200L440,200L440,540Q440,557 428.5,568.5Q417,580 400,580L390,580L390,760Z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/notification_progress.xml b/core/res/res/drawable/notification_progress.xml
new file mode 100644
index 0000000..3a6b600
--- /dev/null
+++ b/core/res/res/drawable/notification_progress.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@id/background"
+          android:gravity="center_vertical|fill_horizontal">
+        <com.android.internal.widget.NotificationProgressDrawable
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:segSegGap="@dimen/notification_progress_segSeg_gap"
+            android:segPointGap="@dimen/notification_progress_segPoint_gap">
+            <segments
+                android:color="?attr/colorProgressBackgroundNormal"
+                android:dashGap="@dimen/notification_progress_segments_dash_gap"
+                android:dashWidth="@dimen/notification_progress_segments_dash_width"
+                android:width="@dimen/notification_progress_segments_height" />
+            <points
+                android:color="?attr/colorProgressBackgroundNormal"
+                android:radius="@dimen/notification_progress_points_radius"
+                android:cornerRadius="@dimen/notification_progress_points_corner_radius"
+                android:inset="@dimen/notification_progress_points_inset" />
+        </com.android.internal.widget.NotificationProgressDrawable>
+    </item>
+</layer-list>
diff --git a/core/res/res/layout/notification_template_material_progress.xml b/core/res/res/layout/notification_template_material_progress.xml
index fdcefcc..75827a2 100644
--- a/core/res/res/layout/notification_template_material_progress.xml
+++ b/core/res/res/layout/notification_template_material_progress.xml
@@ -75,12 +75,11 @@
                         />
 
 
-                    <com.android.internal.widget.NotificationProgressBar
-                        android:id="@+id/progress"
+                    <include
                         android:layout_width="0dp"
-                        android:layout_height="@dimen/notification_progress_bar_height"
-                        style="@style/Widget.Material.Light.ProgressBar.Horizontal"
                         android:layout_weight="1"
+                        android:layout_height="@dimen/notification_progress_tracker_height"
+                        layout="@layout/notification_template_notification_progress_bar"
                         />
 
                     <com.android.internal.widget.CachingIconView
diff --git a/packages/SystemUI/res/layout/udfps_bp_view.xml b/core/res/res/layout/notification_template_notification_progress_bar.xml
similarity index 61%
rename from packages/SystemUI/res/layout/udfps_bp_view.xml
rename to core/res/res/layout/notification_template_notification_progress_bar.xml
index f1c55ef..3574896 100644
--- a/packages/SystemUI/res/layout/udfps_bp_view.xml
+++ b/core/res/res/layout/notification_template_notification_progress_bar.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2014 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -12,11 +12,12 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+  ~ limitations under the License
   -->
-<com.android.systemui.biometrics.UdfpsBpView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
+
+<com.android.internal.widget.NotificationProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/progress"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsBpView>
+    android:layout_height="@dimen/notification_progress_tracker_height"
+    style="@style/Widget.Material.Notification.NotificationProgressBar"
+    />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8a2d767..169cf59 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4447,17 +4447,25 @@
     <string-array translatable="false" name="config_defaultPinnerServiceFiles">
     </string-array>
 
-    <!-- True if camera app should be pinned via Pinner Service -->
+    <!-- Note: This config is deprecated, use config_pinnerCameraPinBytes instead.
+         True if camera app should be pinned via Pinner Service -->
     <bool name="config_pinnerCameraApp">false</bool>
 
-    <!-- Bytes that the PinnerService will pin for Home app -->
-    <integer name="config_pinnerHomePinBytes">0</integer>
+    <!-- Default: 60 MB. Bytes that the PinnerService will pin for Home app -->
+    <integer name="config_pinnerHomePinBytes">62914560</integer>
 
-    <!-- True if assistant app should be pinned via Pinner Service -->
+    <!-- Default: 80 MB. Bytes that the PinnerService will pin for Camera app -->
+    <integer name="config_pinnerCameraPinBytes">83886080</integer>
+
+    <!-- Note: This config is deprecated, use config_pinnerAssistantPinBytes instead.
+         True if assistant app should be pinned via Pinner Service -->
     <bool name="config_pinnerAssistantApp">false</bool>
 
-    <!-- Bytes that the PinnerService will pin for WebView -->
-    <integer name="config_pinnerWebviewPinBytes">0</integer>
+     <!-- Default: 60 MB. Bytes that the PinnerService will pin for Assistant -->
+    <integer name="config_pinnerAssistantPinBytes">62914560</integer>
+
+    <!-- Default: 20 MB. Bytes that the PinnerService will pin for WebView -->
+    <integer name="config_pinnerWebviewPinBytes">20971520</integer>
 
     <!-- Maximum memory that PinnerService will pin for apps expressed
          as a percentage of total device memory [0,100].
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b92aa2f..7184d9a 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -817,6 +817,22 @@
     <dimen name="notification_progress_tracker_width">40dp</dimen>
     <!-- The size of the progress tracker height -->
     <dimen name="notification_progress_tracker_height">20dp</dimen>
+    <!-- The gap between segments in the notification progress bar -->
+    <dimen name="notification_progress_segSeg_gap">2dp</dimen>
+    <!-- The gap between a segment and a point in the notification progress bar -->
+    <dimen name="notification_progress_segPoint_gap">4dp</dimen>
+    <!-- The dash gap of the notification progress bar segments -->
+    <dimen name="notification_progress_segments_dash_gap">9dp</dimen>
+    <!-- The dash width of the notification progress bar segments -->
+    <dimen name="notification_progress_segments_dash_width">3dp</dimen>
+    <!-- The height of the notification progress bar segments -->
+    <dimen name="notification_progress_segments_height">6dp</dimen>
+    <!-- The radius of the notification progress bar points -->
+    <dimen name="notification_progress_points_radius">10dp</dimen>
+    <!-- The corner radius of the notification progress bar points drawn as rects -->
+    <dimen name="notification_progress_points_corner_radius">4dp</dimen>
+    <!-- The inset of the notification progress bar points drawn as rects -->
+    <dimen name="notification_progress_points_inset">0dp</dimen>
 
     <!-- The maximum size of the small notification icon on low memory devices. -->
     <dimen name="notification_small_icon_size_low_ram">@dimen/notification_small_icon_size</dimen>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index eec6ae3..cb8e4aa 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -502,6 +502,10 @@
 
     <style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
 
+    <style name="Widget.Material.Notification.NotificationProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal">
+        <item name="progressDrawable">@drawable/notification_progress</item>
+    </style>
+
     <style name="Widget.Material.Notification.Text" parent="Widget.Material.Light.TextView">
         <item name="lineHeight">20sp</item>
         <item name="textAppearance">@style/TextAppearance.Material.Notification</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4f63fac..ab1b491 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3471,6 +3471,8 @@
   <java-symbol type="array" name="config_defaultPinnerServiceFiles" />
   <java-symbol type="bool" name="config_pinnerCameraApp" />
   <java-symbol type="integer" name="config_pinnerHomePinBytes" />
+  <java-symbol type="integer" name="config_pinnerCameraPinBytes" />
+  <java-symbol type="integer" name="config_pinnerAssistantPinBytes" />
   <java-symbol type="bool" name="config_pinnerAssistantApp" />
   <java-symbol type="integer" name="config_pinnerWebviewPinBytes" />
   <java-symbol type="integer" name="config_pinnerMaxPinnedMemoryPercentage" />
@@ -3864,6 +3866,14 @@
   <java-symbol type="dimen" name="notification_progress_icon_size" />
   <java-symbol type="dimen" name="notification_progress_tracker_width" />
   <java-symbol type="dimen" name="notification_progress_tracker_height" />
+  <java-symbol type="dimen" name="notification_progress_segSeg_gap" />
+  <java-symbol type="dimen" name="notification_progress_segPoint_gap" />
+  <java-symbol type="dimen" name="notification_progress_segments_dash_gap" />
+  <java-symbol type="dimen" name="notification_progress_segments_dash_width" />
+  <java-symbol type="dimen" name="notification_progress_segments_height" />
+  <java-symbol type="dimen" name="notification_progress_points_radius" />
+  <java-symbol type="dimen" name="notification_progress_points_corner_radius" />
+  <java-symbol type="dimen" name="notification_progress_points_inset" />
 
   <java-symbol type="dimen" name="notification_small_icon_size_low_ram"/>
   <java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 48e2620..23a0985 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -2397,10 +2397,25 @@
     public void progressStyle_getProgressMax_returnsSumOfSegmentLength() {
         final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
         progressStyle
+                .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(15),
+                        new Notification.ProgressStyle.Segment(25)))
                 .addProgressSegment(new Notification.ProgressStyle.Segment(10))
                 .addProgressSegment(new Notification.ProgressStyle.Segment(20));
 
-        assertThat(progressStyle.getProgressMax()).isEqualTo(30);
+        assertThat(progressStyle.getProgressMax()).isEqualTo(70);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+    public void progressStyle_getProgressMax_onSetProgressSegments_resets() {
+        final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+        progressStyle
+                .addProgressSegment(new Notification.ProgressStyle.Segment(10))
+                .addProgressSegment(new Notification.ProgressStyle.Segment(20))
+                .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(15),
+                        new Notification.ProgressStyle.Segment(25)));
+
+        assertThat(progressStyle.getProgressMax()).isEqualTo(40);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 25f9cb7..6311298 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -42,6 +42,7 @@
 import android.text.style.ForegroundColorSpan;
 import android.text.style.StrikethroughSpan;
 
+import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -697,7 +698,7 @@
 
             if (drawCommand.path != null) {
                 expect.that(drawCommand.path).isEqualTo(selectionPath);
-                expect.that(drawCommand.paint.getColor()).isEqualTo(Color.YELLOW);
+                expect.that(removeAlpha(drawCommand.paint.getColor())).isEqualTo(Color.YELLOW);
                 expect.that(drawCommand.paint.getBlendMode()).isNotNull();
                 highlightsFound++;
             } else if (drawCommand.text != null) {
@@ -750,7 +751,7 @@
 
             if (drawCommand.path != null) {
                 expect.that(drawCommand.path).isEqualTo(selectionPath);
-                expect.that(drawCommand.paint.getColor()).isEqualTo(Color.YELLOW);
+                expect.that(removeAlpha(drawCommand.paint.getColor())).isEqualTo(Color.YELLOW);
                 expect.that(drawCommand.paint.getBlendMode()).isNotNull();
                 highlightsFound++;
             } else if (drawCommand.text != null) {
@@ -802,7 +803,7 @@
 
             if (drawCommand.path != null) {
                 expect.that(drawCommand.path).isEqualTo(selectionPath);
-                expect.that(drawCommand.paint.getColor()).isEqualTo(Color.CYAN);
+                expect.that(removeAlpha(drawCommand.paint.getColor())).isEqualTo(Color.CYAN);
                 expect.that(drawCommand.paint.getBlendMode()).isNull();
                 highlightsFound++;
             } else if (drawCommand.text != null) {
@@ -855,7 +856,7 @@
 
             if (drawCommand.path != null) {
                 expect.that(drawCommand.path).isEqualTo(selectionPath);
-                expect.that(drawCommand.paint.getColor()).isEqualTo(Color.CYAN);
+                expect.that(removeAlpha(drawCommand.paint.getColor())).isEqualTo(Color.CYAN);
                 expect.that(drawCommand.paint.getBlendMode()).isNull();
                 highlightsFound++;
             } else if (drawCommand.text != null) {
@@ -914,7 +915,7 @@
 
             if (drawCommand.rect != null) {
                 numBackgroundsFound++;
-                expect.that(drawCommand.paint.getColor()).isEqualTo(Color.BLACK);
+                expect.that(removeAlpha(drawCommand.paint.getColor())).isEqualTo(Color.BLACK);
                 expect.that(drawCommand.rect.height()).isAtLeast(LINE_HEIGHT);
                 expect.that(drawCommand.rect.width()).isGreaterThan(0);
                 float expectedY = (numBackgroundsFound) * (LINE_HEIGHT + LINE_DESCENT);
@@ -997,20 +998,38 @@
                 .filter(it -> it.rect != null)
                 .toList();
 
-        expect.that(backgroundCommands.get(0).paint.getColor()).isEqualTo(Color.BLACK);
-        expect.that(backgroundCommands.get(1).paint.getColor()).isEqualTo(Color.WHITE);
-        expect.that(backgroundCommands.get(2).paint.getColor()).isEqualTo(Color.WHITE);
-        expect.that(backgroundCommands.get(3).paint.getColor()).isEqualTo(Color.WHITE);
-        expect.that(backgroundCommands.get(4).paint.getColor()).isEqualTo(Color.WHITE);
-        expect.that(backgroundCommands.get(5).paint.getColor()).isEqualTo(Color.BLACK);
-        expect.that(backgroundCommands.get(6).paint.getColor()).isEqualTo(Color.BLACK);
-        expect.that(backgroundCommands.get(7).paint.getColor()).isEqualTo(Color.BLACK);
-        expect.that(backgroundCommands.get(8).paint.getColor()).isEqualTo(Color.BLACK);
-        expect.that(backgroundCommands.get(9).paint.getColor()).isEqualTo(Color.BLACK);
+        expect.that(removeAlpha(backgroundCommands.get(0).paint.getColor()))
+                .isEqualTo(Color.BLACK);
+        expect.that(removeAlpha(backgroundCommands.get(1).paint.getColor()))
+                .isEqualTo(Color.WHITE);
+        expect.that(removeAlpha(backgroundCommands.get(2).paint.getColor()))
+                .isEqualTo(Color.WHITE);
+        expect.that(removeAlpha(backgroundCommands.get(3).paint.getColor()))
+                .isEqualTo(Color.WHITE);
+        expect.that(removeAlpha(backgroundCommands.get(4).paint.getColor()))
+                .isEqualTo(Color.WHITE);
+        expect.that(removeAlpha(backgroundCommands.get(5).paint.getColor()))
+                .isEqualTo(Color.BLACK);
+        expect.that(removeAlpha(backgroundCommands.get(6).paint.getColor()))
+                .isEqualTo(Color.BLACK);
+        expect.that(removeAlpha(backgroundCommands.get(7).paint.getColor()))
+                .isEqualTo(Color.BLACK);
+        expect.that(removeAlpha(backgroundCommands.get(8).paint.getColor()))
+                .isEqualTo(Color.BLACK);
+        expect.that(removeAlpha(backgroundCommands.get(9).paint.getColor()))
+                .isEqualTo(Color.BLACK);
 
         expect.that(backgroundCommands.size()).isEqualTo(backgroundRectsDrawn);
     }
 
+    private int removeAlpha(int color) {
+        return Color.rgb(
+                Color.red(color),
+                Color.green(color),
+                Color.blue(color)
+        );
+    }
+
     private static final class MockCanvas extends Canvas {
 
         static class DrawCommand {
@@ -1122,6 +1141,11 @@
             mDrawCommands.add(new DrawCommand(rect, p));
         }
 
+        @Override
+        public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
+            mDrawCommands.add(new DrawCommand(rect, paint));
+        }
+
         List<DrawCommand> getDrawCommands() {
             return mDrawCommands;
         }
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 0621d82..2880ecf 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import static android.appwidget.flags.Flags.remoteAdapterConversion;
+
 import static com.android.internal.R.id.pending_intent_tag;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -282,7 +284,10 @@
         widget.addView(view);
 
         ListView listView = (ListView) view.findViewById(R.id.list);
-        listView.onRemoteAdapterConnected();
+
+        if (!remoteAdapterConversion()) {
+            listView.onRemoteAdapterConnected();
+        }
         assertNotNull(listView.getAdapter());
 
         top.reapply(mContext, view);
@@ -414,6 +419,58 @@
         assertNotNull(view.findViewById(R.id.light_background_text));
     }
 
+    @Test
+    public void remoteCollectionItemsAdapter_lightBackgroundLayoutFlagSet() {
+        AppWidgetHostView widget = new AppWidgetHostView(mContext);
+        RemoteViews container = new RemoteViews(mPackage, R.layout.remote_view_host);
+        RemoteViews listRemoteViews = new RemoteViews(mPackage, R.layout.remote_views_list);
+        RemoteViews item = new RemoteViews(mPackage, R.layout.remote_views_text);
+        item.setLightBackgroundLayoutId(R.layout.remote_views_light_background_text);
+        listRemoteViews.setRemoteAdapter(
+                R.id.list,
+                new RemoteViews.RemoteCollectionItems.Builder().addItem(0, item).build());
+        container.addView(R.id.container, listRemoteViews);
+
+        widget.setOnLightBackground(true);
+        widget.updateAppWidget(container);
+
+        // Populate the list view
+        ListView listView = (ListView) widget.findViewById(R.id.list);
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+        listView.measure(measureSpec, measureSpec);
+        listView.layout(0, 0, 100, 100);
+
+        // Picks the light background layout id for the item
+        assertNotNull(listView.getChildAt(0).findViewById(R.id.light_background_text));
+        assertNull(listView.getChildAt(0).findViewById(R.id.text));
+    }
+
+    @Test
+    public void remoteCollectionItemsAdapter_lightBackgroundLayoutFlagNotSet() {
+        AppWidgetHostView widget = new AppWidgetHostView(mContext);
+        RemoteViews container = new RemoteViews(mPackage, R.layout.remote_view_host);
+        RemoteViews listRemoteViews = new RemoteViews(mPackage, R.layout.remote_views_list);
+        RemoteViews item = new RemoteViews(mPackage, R.layout.remote_views_text);
+        item.setLightBackgroundLayoutId(R.layout.remote_views_light_background_text);
+        listRemoteViews.setRemoteAdapter(
+                R.id.list,
+                new RemoteViews.RemoteCollectionItems.Builder().addItem(0, item).build());
+        container.addView(R.id.container, listRemoteViews);
+
+        widget.setOnLightBackground(false);
+        widget.updateAppWidget(container);
+
+        // Populate the list view
+        ListView listView = (ListView) widget.findViewById(R.id.list);
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+        listView.measure(measureSpec, measureSpec);
+        listView.layout(0, 0, 100, 100);
+
+        // Does not pick the light background layout id for the item
+        assertNotNull(listView.getChildAt(0).findViewById(R.id.text));
+        assertNull(listView.getChildAt(0).findViewById(R.id.light_background_text));
+    }
+
     private RemoteViews createViewChained(int depth, String... texts) {
         RemoteViews result = new RemoteViews(mPackage, R.layout.remote_view_host);
 
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index b001cc2..46bd73e 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -21,6 +21,7 @@
 import static android.window.OnBackInvokedDispatcher.PRIORITY_SYSTEM_NAVIGATION_OBSERVER;
 
 import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER;
+import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_TIMESTAMP_API;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -486,6 +487,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(FLAG_PREDICTIVE_BACK_TIMESTAMP_API)
     public void onBackInvoked_notCalledAfterCallbackUnregistration()
             throws RemoteException, InterruptedException {
         // Setup a callback that unregisters itself after the gesture is finished but before the
@@ -684,6 +686,7 @@
         return new BackMotionEvent(
                 /* touchX = */ 0,
                 /* touchY = */ 0,
+                /* frameTime = */ 0,
                 /* progress = */ progress,
                 /* triggerBack = */ false,
                 /* swipeEdge = */ BackEvent.EDGE_LEFT,
diff --git a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
index 6419c1e0..79a478a 100644
--- a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
@@ -254,7 +254,6 @@
 
         // Colors with 50% opacity
         int fadedGreen = 0x7F00FF00;
-        int fadedBlue = 0x7F0000FF;
         int fadedYellow = 0x7FFFFF00;
 
         List<Part> expected = new ArrayList<>(List.of(
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
index e3a1d8a..6ad2f08 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
@@ -148,8 +148,12 @@
             final TaskFragmentInfo info = mTaskFragmentInfos.valueAt(i);
             mPresenter.deleteTaskFragment(wct, info.getFragmentToken());
         }
-        mPresenter.setSavedState(new Bundle());
 
+        removeSavedState();
+    }
+
+    private void removeSavedState() {
+        mPresenter.setSavedState(new Bundle());
         mParcelableTaskContainerDataList.clear();
         mTaskFragmentInfos.clear();
         mTaskFragmentParentInfos.clear();
@@ -169,6 +173,19 @@
             return false;
         }
 
+        if (mTaskFragmentParentInfos.size() == 0) {
+            // No Task left in the WM hierarchy, remove the states and no need to restore.
+            if (DEBUG) Log.d(TAG, "Remove save states due to no task to restore.");
+            removeSavedState();
+            return false;
+        }
+
+        final ArrayList<Integer> taskIdsInSystem = new ArrayList<>();
+        for (int i = mTaskFragmentParentInfos.size() - 1; i >= 0; --i) {
+            final TaskFragmentParentInfo parentInfo = mTaskFragmentParentInfos.valueAt(i);
+            taskIdsInSystem.add(parentInfo.getTaskId());
+        }
+
         if (DEBUG) Log.d(TAG, "Rebuilding TaskContainers.");
         final ArrayMap<String, EmbeddingRule> embeddingRuleMap = new ArrayMap<>();
         for (EmbeddingRule rule : rules) {
@@ -190,6 +207,14 @@
             }
 
             mParcelableTaskContainerDataList.remove(parcelableTaskContainerData);
+            if (!taskIdsInSystem.contains(parcelableTaskContainerData.mTaskId)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Rebuilding TaskContainer abort! Not existed. Task#"
+                            + parcelableTaskContainerData.mTaskId);
+                }
+                continue;
+            }
+
             final TaskContainer taskContainer = new TaskContainer(parcelableTaskContainerData,
                     mController, mTaskFragmentInfos);
             if (DEBUG) Log.d(TAG, "Created TaskContainer " + taskContainer);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 8345b40..3368e2e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -239,6 +239,11 @@
         mActivityStartMonitor = new ActivityStartMonitor();
         instrumentation.addMonitor(mActivityStartMonitor);
         foldingFeatureProducer.addDataChangedCallback(new FoldingFeatureListener());
+
+        synchronized (mLock) {
+            // Abort the restoration if any and the application already has running activities.
+            abortRebuildingTaskContainersIfNeeded(null /* launchingActivity */);
+        }
     }
 
     private class FoldingFeatureListener
@@ -285,6 +290,10 @@
                 return;
             }
 
+            if (abortRebuildingTaskContainersIfNeeded(null /* launchingActivity */)) {
+                return;
+            }
+
             try {
                 final TransactionRecord transactionRecord =
                         mTransactionManager.startNewTransaction();
@@ -2883,6 +2892,53 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private boolean abortRebuildingTaskContainersIfNeeded(@Nullable Activity launchingActivity) {
+        if (mPresenter == null || !mPresenter.isWaitingToRebuildTaskContainers()) {
+            return false;
+        }
+
+        final ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread == null) {
+            return false;
+        }
+
+        final Activity lastCreatedActivity = activityThread.getLastCreatedActivity();
+        final Activity activity =
+                launchingActivity != null ? launchingActivity : lastCreatedActivity;
+        if (activity == null) {
+            return false;
+        }
+
+        Log.w(TAG, "Rebuilding aborted, clean up.");
+
+        // Retrieve the Task intent.
+        final int taskId = getTaskId(activity);
+
+        // Clean up and abort the restoration
+        // TODO(b/369488857): also to remove the non-organized activities in the Task?
+        final TransactionRecord transactionRecord =
+                mTransactionManager.startNewTransaction();
+        final WindowContainerTransaction wct = transactionRecord.getTransaction();
+        mPresenter.abortTaskContainerRebuilding(wct);
+        transactionRecord.apply(false /* shouldApplyIndependently */);
+
+        // Start the Task root activity if the task is now empty.
+        ActivityManager.RecentTaskInfo taskInfo = null;
+        final ActivityManager am = activity.getSystemService(ActivityManager.class);
+        final List<ActivityManager.AppTask> appTasks = am.getAppTasks();
+        for (ActivityManager.AppTask appTask : appTasks) {
+            if (appTask.getTaskInfo().taskId == taskId) {
+                taskInfo = appTask.getTaskInfo();
+                break;
+            }
+        }
+        if (taskInfo != null && !taskInfo.isRunning) {
+            activity.startActivity(taskInfo.baseIntent.cloneFilter());
+        }
+        return true;
+    }
+
     private final class LifecycleCallbacks extends EmptyLifecycleCallbacksAdapter {
 
         @Override
@@ -2894,33 +2950,7 @@
                 return;
             }
             synchronized (mLock) {
-                if (mPresenter.isWaitingToRebuildTaskContainers()) {
-                    Log.w(TAG, "Rebuilding aborted, clean up and restart");
-
-                    // Retrieve the Task intent.
-                    final int taskId = getTaskId(activity);
-                    Intent taskIntent = null;
-                    final ActivityManager am = activity.getSystemService(ActivityManager.class);
-                    final List<ActivityManager.AppTask> appTasks = am.getAppTasks();
-                    for (ActivityManager.AppTask appTask : appTasks) {
-                        if (appTask.getTaskInfo().taskId == taskId) {
-                            taskIntent = appTask.getTaskInfo().baseIntent.cloneFilter();
-                            break;
-                        }
-                    }
-
-                    // Clean up and abort the restoration
-                    // TODO(b/369488857): also to remove the non-organized activities in the Task?
-                    final TransactionRecord transactionRecord =
-                            mTransactionManager.startNewTransaction();
-                    final WindowContainerTransaction wct = transactionRecord.getTransaction();
-                    mPresenter.abortTaskContainerRebuilding(wct);
-                    transactionRecord.apply(false /* shouldApplyIndependently */);
-
-                    // Start the Task root activity.
-                    if (taskIntent != null) {
-                        activity.startActivity(taskIntent);
-                    }
+                if (abortRebuildingTaskContainersIfNeeded(activity)) {
                     return;
                 }
 
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
index 61cd1c3..5a2a723 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
@@ -61,11 +61,30 @@
     @IntDef(prefix = {"SPLIT_POSITION_"}, value = {
             SPLIT_POSITION_UNDEFINED,
             SPLIT_POSITION_TOP_OR_LEFT,
-            SPLIT_POSITION_BOTTOM_OR_RIGHT
+            SPLIT_POSITION_BOTTOM_OR_RIGHT,
     })
     public @interface SplitPosition {
     }
 
+    // These SPLIT_INDEX constants will be used in the same way as the above SPLIT_POSITION ints,
+    // but scalable to n apps. Eventually, SPLIT_POSITION can be deprecated and only the below
+    // will be used.
+    public static final int SPLIT_INDEX_UNDEFINED = -1;
+    public static final int SPLIT_INDEX_0 = 0;
+    public static final int SPLIT_INDEX_1 = 1;
+    public static final int SPLIT_INDEX_2 = 2;
+    public static final int SPLIT_INDEX_3 = 3;
+
+    @IntDef(prefix = {"SPLIT_INDEX_"}, value = {
+            SPLIT_INDEX_UNDEFINED,
+            SPLIT_INDEX_0,
+            SPLIT_INDEX_1,
+            SPLIT_INDEX_2,
+            SPLIT_INDEX_3
+    })
+    public @interface SplitIndex {
+    }
+
     /**
      * A snap target for two apps, where the split is 33-66. With FLAG_ENABLE_FLEXIBLE_SPLIT,
      * only used on tablets.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index b90e6e2..19b51f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -355,11 +355,8 @@
                 int keyAction,
                 @BackEvent.SwipeEdge int swipeEdge
         ) {
-            mShellExecutor.execute(() -> onMotionEvent(
-                    /* touchX = */ touchX,
-                    /* touchY = */ touchY,
-                    /* keyAction = */ keyAction,
-                    /* swipeEdge = */ swipeEdge));
+            mShellExecutor.execute(
+                    () -> onMotionEvent(touchX, touchY, keyAction, swipeEdge));
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index a8a8c2a..eb9cdab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1246,9 +1246,12 @@
      */
     public void dragBubbleToDismiss(String bubbleKey, long timestamp) {
         String selectedBubbleKey = mBubbleData.getSelectedBubbleKey();
-        if (mBubbleData.hasAnyBubbleWithKey(bubbleKey)) {
+        Bubble bubbleToDismiss = mBubbleData.getAnyBubbleWithkey(bubbleKey);
+        if (bubbleToDismiss != null) {
             mBubbleData.dismissBubbleWithKey(
                     bubbleKey, Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, timestamp);
+            mLogger.log(bubbleToDismiss,
+                    BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE);
         }
         if (mBubbleData.hasBubbles()) {
             // We still have bubbles, if we dragged an individual bubble to dismiss we were expanded
@@ -1979,11 +1982,15 @@
 
         @Override
         public void addBubble(Bubble addedBubble) {
+            // Only log metrics event
+            mLogger.log(addedBubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED);
             // Nothing to do for adds, these are handled by launcher / in the bubble bar.
         }
 
         @Override
         public void updateBubble(Bubble updatedBubble) {
+            // Only log metrics event
+            mLogger.log(updatedBubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_UPDATED);
             // Nothing to do for updates, these are handled by launcher / in the bubble bar.
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index 1abe119..6d757d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.bubbles;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.FrameworkStatsLog;
@@ -33,7 +32,6 @@
     /**
      * Bubble UI event.
      */
-    @VisibleForTesting
     public enum Event implements UiEventLogger.UiEventEnum {
 
         // region bubble events
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index 9f100fa..8592170 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -19,9 +19,11 @@
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
 
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_33_66;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_66_33;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_MINIMIZE;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_NONE;
@@ -33,6 +35,9 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.wm.shell.Flags;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+
 import java.util.ArrayList;
 
 /**
@@ -79,8 +84,10 @@
     private final int mTaskHeightInMinimizedMode;
     private final float mFixedRatio;
     /** Allows split ratios to calculated dynamically instead of using {@link #mFixedRatio}. */
-    private final boolean mAllowFlexibleSplitRatios;
-    private final boolean mIsHorizontalDivision;
+    private final boolean mCalculateRatiosBasedOnAvailableSpace;
+    /** Allows split ratios that go offscreen (a.k.a. "flexible split") */
+    private final boolean mAllowOffscreenRatios;
+    private final boolean mIsLeftRightSplit;
 
     /** The first target which is still splitting the screen */
     private final SnapTarget mFirstSplitTarget;
@@ -94,13 +101,13 @@
 
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
-        boolean isHorizontalDivision, Rect insets, int dockSide) {
-        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
-            dockSide, false /* minimized */, true /* resizable */);
+            boolean isLeftRightSplit, Rect insets, int dockSide) {
+        this(res, displayWidth, displayHeight, dividerSize, isLeftRightSplit, insets,
+                dockSide, false /* minimized */, true /* resizable */);
     }
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
-            boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode,
+            boolean isLeftRightSplit, Rect insets, int dockSide, boolean isMinimizedMode,
             boolean isHomeResizable) {
         mMinFlingVelocityPxPerSecond =
                 MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
@@ -109,7 +116,7 @@
         mDividerSize = dividerSize;
         mDisplayWidth = displayWidth;
         mDisplayHeight = displayHeight;
-        mIsHorizontalDivision = isHorizontalDivision;
+        mIsLeftRightSplit = isLeftRightSplit;
         mInsets.set(insets);
         mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED :
                 res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode);
@@ -119,11 +126,14 @@
                 com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
         mMinimalSizeResizableTask = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_resizable_task);
-        mAllowFlexibleSplitRatios = res.getBoolean(
+        mCalculateRatiosBasedOnAvailableSpace = res.getBoolean(
                 com.android.internal.R.bool.config_flexibleSplitRatios);
+        // If this is a small screen or a foldable, use offscreen ratios
+        mAllowOffscreenRatios =
+                Flags.enableFlexibleTwoAppSplit() && SplitScreenUtils.allowOffscreenRatios(res);
         mTaskHeightInMinimizedMode = isHomeResizable ? res.getDimensionPixelSize(
                 com.android.internal.R.dimen.task_height_of_minimized_mode) : 0;
-        calculateTargets(isHorizontalDivision, dockSide);
+        calculateTargets(isLeftRightSplit, dockSide);
         mFirstSplitTarget = mTargets.get(1);
         mLastSplitTarget = mTargets.get(mTargets.size() - 2);
         mDismissStartTarget = mTargets.get(0);
@@ -208,18 +218,18 @@
     }
 
     private int getStartInset() {
-        if (mIsHorizontalDivision) {
-            return mInsets.top;
-        } else {
+        if (mIsLeftRightSplit) {
             return mInsets.left;
+        } else {
+            return mInsets.top;
         }
     }
 
     private int getEndInset() {
-        if (mIsHorizontalDivision) {
-            return mInsets.bottom;
-        } else {
+        if (mIsLeftRightSplit) {
             return mInsets.right;
+        } else {
+            return mInsets.bottom;
         }
     }
 
@@ -233,6 +243,11 @@
         return mFirstSplitTarget.position < position && position < mLastSplitTarget.position;
     }
 
+    /** Returns if we are currently on a device/screen that supports split apps going offscreen. */
+    public boolean areOffscreenRatiosSupported() {
+        return mAllowOffscreenRatios;
+    }
+
     private SnapTarget snap(int position, boolean hardDismiss) {
         if (shouldApplyFreeSnapMode(position)) {
             return new SnapTarget(position, SNAP_TO_NONE);
@@ -254,11 +269,11 @@
         return mTargets.get(minIndex);
     }
 
-    private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
+    private void calculateTargets(boolean isLeftRightSplit, int dockedSide) {
         mTargets.clear();
-        int dividerMax = isHorizontalDivision
-                ? mDisplayHeight
-                : mDisplayWidth;
+        int dividerMax = isLeftRightSplit
+                ? mDisplayWidth
+                : mDisplayHeight;
         int startPos = -mDividerSize;
         if (dockedSide == DOCKED_RIGHT) {
             startPos += mInsets.left;
@@ -266,57 +281,65 @@
         mTargets.add(new SnapTarget(startPos, SNAP_TO_START_AND_DISMISS, 0.35f));
         switch (mSnapMode) {
             case SNAP_MODE_16_9:
-                addRatio16_9Targets(isHorizontalDivision, dividerMax);
+                addRatio16_9Targets(isLeftRightSplit, dividerMax);
                 break;
             case SNAP_FIXED_RATIO:
-                addFixedDivisionTargets(isHorizontalDivision, dividerMax);
+                addFixedDivisionTargets(isLeftRightSplit, dividerMax);
                 break;
             case SNAP_ONLY_1_1:
-                addMiddleTarget(isHorizontalDivision);
+                addMiddleTarget(isLeftRightSplit);
                 break;
             case SNAP_MODE_MINIMIZED:
-                addMinimizedTarget(isHorizontalDivision, dockedSide);
+                addMinimizedTarget(isLeftRightSplit, dockedSide);
                 break;
         }
         mTargets.add(new SnapTarget(dividerMax, SNAP_TO_END_AND_DISMISS, 0.35f));
     }
 
-    private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
+    private void addNonDismissingTargets(boolean isLeftRightSplit, int topPosition,
             int bottomPosition, int dividerMax) {
-        maybeAddTarget(topPosition, topPosition - getStartInset(), SNAP_TO_2_33_66);
-        addMiddleTarget(isHorizontalDivision);
+        @PersistentSnapPosition int firstTarget =
+                mAllowOffscreenRatios ? SNAP_TO_2_10_90 : SNAP_TO_2_33_66;
+        @PersistentSnapPosition int lastTarget =
+                mAllowOffscreenRatios ? SNAP_TO_2_90_10 : SNAP_TO_2_66_33;
+        maybeAddTarget(topPosition, topPosition - getStartInset(), firstTarget);
+        addMiddleTarget(isLeftRightSplit);
         maybeAddTarget(bottomPosition,
-                dividerMax - getEndInset() - (bottomPosition + mDividerSize), SNAP_TO_2_66_33);
+                dividerMax - getEndInset() - (bottomPosition + mDividerSize), lastTarget);
     }
 
-    private void addFixedDivisionTargets(boolean isHorizontalDivision, int dividerMax) {
-        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
-        int end = isHorizontalDivision
-                ? mDisplayHeight - mInsets.bottom
-                : mDisplayWidth - mInsets.right;
+    private void addFixedDivisionTargets(boolean isLeftRightSplit, int dividerMax) {
+        int start = isLeftRightSplit ? mInsets.left : mInsets.top;
+        int end = isLeftRightSplit
+                ? mDisplayWidth - mInsets.right
+                : mDisplayHeight - mInsets.bottom;
         int size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
-        if (mAllowFlexibleSplitRatios) {
+
+        if (mAllowOffscreenRatios) {
+            // TODO (b/349828130): This is a placeholder value, real measurements to come
+            size = (int) (0.3f * (end - start)) - mDividerSize / 2;
+        } else if (mCalculateRatiosBasedOnAvailableSpace) {
             size = Math.max(size, mMinimalSizeResizableTask);
         }
         int topPosition = start + size;
         int bottomPosition = end - size - mDividerSize;
-        addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
+        addNonDismissingTargets(isLeftRightSplit, topPosition, bottomPosition, dividerMax);
     }
 
-    private void addRatio16_9Targets(boolean isHorizontalDivision, int dividerMax) {
-        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
-        int end = isHorizontalDivision
-                ? mDisplayHeight - mInsets.bottom
-                : mDisplayWidth - mInsets.right;
-        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
-        int endOther = isHorizontalDivision
+    private void addRatio16_9Targets(boolean isLeftRightSplit, int dividerMax) {
+        int start = isLeftRightSplit ? mInsets.left : mInsets.top;
+        int end = isLeftRightSplit
                 ? mDisplayWidth - mInsets.right
                 : mDisplayHeight - mInsets.bottom;
+        int startOther = isLeftRightSplit ? mInsets.top : mInsets.left;
+        int endOther = isLeftRightSplit
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
         float size = 9.0f / 16.0f * (endOther - startOther);
         int sizeInt = (int) Math.floor(size);
         int topPosition = start + sizeInt;
         int bottomPosition = end - sizeInt - mDividerSize;
-        addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
+        addNonDismissingTargets(isLeftRightSplit, topPosition, bottomPosition, dividerMax);
     }
 
     /**
@@ -324,22 +347,22 @@
      * meets the minimal size requirement.
      */
     private void maybeAddTarget(int position, int smallerSize, @SnapPosition int snapPosition) {
-        if (smallerSize >= mMinimalSizeResizableTask) {
+        if (smallerSize >= mMinimalSizeResizableTask || mAllowOffscreenRatios) {
             mTargets.add(new SnapTarget(position, snapPosition));
         }
     }
 
-    private void addMiddleTarget(boolean isHorizontalDivision) {
-        int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+    private void addMiddleTarget(boolean isLeftRightSplit) {
+        int position = DockedDividerUtils.calculateMiddlePosition(isLeftRightSplit,
                 mInsets, mDisplayWidth, mDisplayHeight, mDividerSize);
         mTargets.add(new SnapTarget(position, SNAP_TO_2_50_50));
     }
 
-    private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
+    private void addMinimizedTarget(boolean isLeftRightSplit, int dockedSide) {
         // In portrait offset the position by the statusbar height, in landscape add the statusbar
         // height as well to match portrait offset
         int position = mTaskHeightInMinimizedMode + mInsets.top;
-        if (!isHorizontalDivision) {
+        if (isLeftRightSplit) {
             if (dockedSide == DOCKED_LEFT) {
                 position += mInsets.left;
             } else if (dockedSide == DOCKED_RIGHT) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java
index f25dfea..25157c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java
@@ -97,12 +97,12 @@
         }
     }
 
-    public static int calculateMiddlePosition(boolean isHorizontalDivision, Rect insets,
+    public static int calculateMiddlePosition(boolean isLeftRightSplit, Rect insets,
             int displayWidth, int displayHeight, int dividerSize) {
-        int start = isHorizontalDivision ? insets.top : insets.left;
-        int end = isHorizontalDivision
-                ? displayHeight - insets.bottom
-                : displayWidth - insets.right;
+        int start = isLeftRightSplit ? insets.left : insets.top;
+        int end = isLeftRightSplit
+                ? displayWidth - insets.right
+                : displayHeight - insets.bottom;
         return start + (end - start) / 2 - dividerSize / 2;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 83ffaf4..f73065ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -30,6 +30,8 @@
 import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED;
 import static com.android.wm.shell.shared.animation.Interpolators.LINEAR;
 import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_END_AND_DISMISS;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_START_AND_DISMISS;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -438,12 +440,31 @@
             dividerBounds.right = dividerBounds.left + mDividerWindowWidth;
             bounds1.right = position;
             bounds2.left = bounds1.right + mDividerSize;
+
+            // For flexible split, expand app offscreen as well
+            if (mDividerSnapAlgorithm.areOffscreenRatiosSupported()) {
+                if (position <= mDividerSnapAlgorithm.getMiddleTarget().position) {
+                    bounds1.left = bounds1.right - bounds2.width();
+                } else {
+                    bounds2.right = bounds2.left + bounds1.width();
+                }
+            }
+
         } else {
             position += mRootBounds.top;
             dividerBounds.top = position - mDividerInsets;
             dividerBounds.bottom = dividerBounds.top + mDividerWindowWidth;
             bounds1.bottom = position;
             bounds2.top = bounds1.bottom + mDividerSize;
+
+            // For flexible split, expand app offscreen as well
+            if (mDividerSnapAlgorithm.areOffscreenRatiosSupported()) {
+                if (position <= mDividerSnapAlgorithm.getMiddleTarget().position) {
+                    bounds1.top = bounds1.bottom - bounds2.width();
+                } else {
+                    bounds2.bottom = bounds2.top + bounds1.width();
+                }
+            }
         }
         DockedDividerUtils.sanitizeStackBounds(bounds1, true /** topLeft */);
         DockedDividerUtils.sanitizeStackBounds(bounds2, false /** topLeft */);
@@ -644,7 +665,7 @@
                 rootBounds.width(),
                 rootBounds.height(),
                 mDividerSize,
-                !mIsLeftRightSplit,
+                mIsLeftRightSplit,
                 insets,
                 mIsLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
     }
@@ -669,6 +690,21 @@
                 });
     }
 
+    /**
+     * Moves the divider to the other side of the screen. Does nothing if the divider is in the
+     * center.
+     * TODO (b/349828130): Currently only supports the two-app case. For n-apps,
+     *  DividerSnapAlgorithm will need to be refactored, and this function will change as well.
+     */
+    public void flingDividerToOtherSide(@PersistentSnapPosition int currentSnapPosition) {
+        switch (currentSnapPosition) {
+            case SNAP_TO_2_10_90 ->
+                    snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getLastSplitTarget());
+            case SNAP_TO_2_90_10 ->
+                    snapToTarget(mDividerPosition, mDividerSnapAlgorithm.getFirstSplitTarget());
+        }
+    }
+
     @VisibleForTesting
     void flingDividerPosition(int from, int to, int duration,
             @Nullable Runnable flingFinishedCallback) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index bdbcb46..65bf389 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -18,6 +18,10 @@
 
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_10_45_45;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_45_45_10;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -38,6 +42,8 @@
 
 /** Helper utility class for split screen components to use. */
 public class SplitScreenUtils {
+    private static final int LARGE_SCREEN_MIN_EDGE_DP = 600;
+
     /** Reverse the split position. */
     @SplitScreenConstants.SplitPosition
     public static int reverseSplitPosition(@SplitScreenConstants.SplitPosition int position) {
@@ -110,10 +116,9 @@
             Configuration config) {
         // Compare the max bounds sizes as on near-square devices, the insets may result in a
         // configuration in the other orientation
-        final boolean isLargeScreen = config.smallestScreenWidthDp >= 600;
         final Rect maxBounds = config.windowConfiguration.getMaxBounds();
         final boolean isLandscape = maxBounds.width() >= maxBounds.height();
-        return isLeftRightSplit(allowLeftRightSplitInPortrait, isLargeScreen, isLandscape);
+        return isLeftRightSplit(allowLeftRightSplitInPortrait, isLargeScreen(config), isLandscape);
     }
 
     /**
@@ -128,4 +133,41 @@
             return isLandscape;
         }
     }
+
+    /**
+     * Returns whether the current config is a large screen (tablet or unfolded foldable)
+     */
+    public static boolean isLargeScreen(Configuration config) {
+        return config.smallestScreenWidthDp >= LARGE_SCREEN_MIN_EDGE_DP;
+    }
+
+    /**
+     * Returns whether we should allow split ratios to go offscreen or not. If the device is a phone
+     * or a foldable (either screen), we allow it.
+     */
+    public static boolean allowOffscreenRatios(Resources res) {
+        return !isLargeScreen(res.getConfiguration())
+                ||
+                res.getIntArray(com.android.internal.R.array.config_foldedDeviceStates).length != 0;
+    }
+
+    /**
+     * Within a particular split layout, we label the stages numerically: 0, 1, 2... from left to
+     * right (or top to bottom). This function takes in a stage index (0th, 1st, 2nd...) and a
+     * PersistentSnapPosition and returns if that particular stage is offscreen in that layout.
+     */
+    public static boolean isPartiallyOffscreen(int stageIndex,
+            @SplitScreenConstants.PersistentSnapPosition int snapPosition) {
+        switch(snapPosition) {
+            case SNAP_TO_2_10_90:
+            case SNAP_TO_3_10_45_45:
+                return stageIndex == 0;
+            case SNAP_TO_2_90_10:
+                return stageIndex == 1;
+            case SNAP_TO_3_45_45_10:
+                return stageIndex == 2;
+            default:
+                return false;
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index 379e052..8ebe503 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -21,17 +21,39 @@
 import com.android.internal.util.FrameworkStatsLog
 import com.android.window.flags.Flags
 import com.android.wm.shell.EventLogTags
-import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import java.security.SecureRandom
+import java.util.Random
+import java.util.concurrent.atomic.AtomicInteger
+
 
 /** Event logger for logging desktop mode session events */
 class DesktopModeEventLogger {
+    private val random: Random = SecureRandom()
+
+    /** The session id for the current desktop mode session */
+    @VisibleForTesting
+    val currentSessionId: AtomicInteger = AtomicInteger(NO_SESSION_ID)
+
+    private fun generateSessionId() = 1 + random.nextInt(1 shl 20)
+
     /**
-     * Logs the enter of desktop mode having session id [sessionId] and the reason [enterReason] for
-     * entering desktop mode
+     * Logs enter into desktop mode with [enterReason]
      */
-    fun logSessionEnter(sessionId: Int, enterReason: EnterReason) {
+    fun logSessionEnter(enterReason: EnterReason) {
+        val sessionId = generateSessionId()
+        val previousSessionId = currentSessionId.getAndSet(sessionId)
+        if (previousSessionId != NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: Existing desktop mode session id: %s found on desktop "
+                    + "mode enter",
+                previousSessionId
+            )
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging session enter, session: %s reason: %s",
             sessionId,
             enterReason.name
@@ -47,12 +69,20 @@
     }
 
     /**
-     * Logs the exit of desktop mode having session id [sessionId] and the reason [exitReason] for
-     * exiting desktop mode
+     * Logs exit from desktop mode session with [exitReason]
      */
-    fun logSessionExit(sessionId: Int, exitReason: ExitReason) {
+    fun logSessionExit(exitReason: ExitReason) {
+        val sessionId = currentSessionId.getAndSet(NO_SESSION_ID)
+        if (sessionId == NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: No session id found for logging exit from desktop mode"
+            )
+            return
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging session exit, session: %s reason: %s",
             sessionId,
             exitReason.name
@@ -68,12 +98,20 @@
     }
 
     /**
-     * Logs that the task with update [taskUpdate] was added in the desktop mode session having
-     * session id [sessionId]
+     * Logs that a task with [taskUpdate] was added in a desktop mode session
      */
-    fun logTaskAdded(sessionId: Int, taskUpdate: TaskUpdate) {
+    fun logTaskAdded(taskUpdate: TaskUpdate) {
+        val sessionId = currentSessionId.get()
+        if (sessionId == NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: No session id found for logging task added"
+            )
+            return
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging task added, session: %s taskId: %s",
             sessionId,
             taskUpdate.instanceId
@@ -85,12 +123,20 @@
     }
 
     /**
-     * Logs that the task with update [taskUpdate] was removed in the desktop mode session having
-     * session id [sessionId]
+     * Logs that a task with [taskUpdate] was removed from a desktop mode session
      */
-    fun logTaskRemoved(sessionId: Int, taskUpdate: TaskUpdate) {
+    fun logTaskRemoved(taskUpdate: TaskUpdate) {
+        val sessionId = currentSessionId.get()
+        if (sessionId == NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: No session id found for logging task removed"
+            )
+            return
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging task remove, session: %s taskId: %s",
             sessionId,
             taskUpdate.instanceId
@@ -102,12 +148,20 @@
     }
 
     /**
-     * Logs that the task with update [taskUpdate] had it's info changed in the desktop mode session
-     * having session id [sessionId]
+     * Logs that a task with [taskUpdate] had it's info changed in a desktop mode session
      */
-    fun logTaskInfoChanged(sessionId: Int, taskUpdate: TaskUpdate) {
+    fun logTaskInfoChanged(taskUpdate: TaskUpdate) {
+        val sessionId = currentSessionId.get()
+        if (sessionId == NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: No session id found for logging task info changed"
+            )
+            return
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging task info changed, session: %s taskId: %s",
             sessionId,
             taskUpdate.instanceId
@@ -119,14 +173,23 @@
     }
 
     /**
-     * Logs that a task resize event is starting with [taskSizeUpdate] within a
-     * Desktop mode [sessionId].
+     * Logs that a task resize event is starting with [taskSizeUpdate] within a Desktop mode
+     * session.
      */
-    fun logTaskResizingStarted(sessionId: Int, taskSizeUpdate: TaskSizeUpdate) {
+    fun logTaskResizingStarted(taskSizeUpdate: TaskSizeUpdate) {
         if (!Flags.enableResizingMetrics()) return
 
+        val sessionId = currentSessionId.get()
+        if (sessionId == NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: No session id found for logging start of task resizing"
+            )
+            return
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging task resize is starting, session: %s taskId: %s",
             sessionId,
             taskSizeUpdate.instanceId
@@ -138,14 +201,22 @@
     }
 
     /**
-     * Logs that a task resize event is ending with [taskSizeUpdate] within a
-     * Desktop mode [sessionId].
+     * Logs that a task resize event is ending with [taskSizeUpdate] within a Desktop mode session.
      */
-    fun logTaskResizingEnded(sessionId: Int, taskSizeUpdate: TaskSizeUpdate) {
+    fun logTaskResizingEnded(taskSizeUpdate: TaskSizeUpdate) {
         if (!Flags.enableResizingMetrics()) return
 
+        val sessionId = currentSessionId.get()
+        if (sessionId == NO_SESSION_ID) {
+            ProtoLog.w(
+                WM_SHELL_DESKTOP_MODE,
+                "DesktopModeLogger: No session id found for logging end of task resizing"
+            )
+            return
+        }
+
         ProtoLog.v(
-            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            WM_SHELL_DESKTOP_MODE,
             "DesktopModeLogger: Logging task resize is ending, session: %s taskId: %s",
             sessionId,
             taskSizeUpdate.instanceId
@@ -248,6 +319,7 @@
     }
 
     companion object {
+
         /**
          * Describes a task position and dimensions.
          *
@@ -465,5 +537,6 @@
             FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE
         private const val DESKTOP_MODE_TASK_SIZE_UPDATED_ATOM_ID =
             FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED
+        @VisibleForTesting const val NO_SESSION_ID = 0
     }
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index f847aa89..ed03982 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -35,8 +35,6 @@
 import androidx.core.util.isNotEmpty
 import androidx.core.util.plus
 import androidx.core.util.putAll
-import com.android.internal.logging.InstanceId
-import com.android.internal.logging.InstanceIdSequence
 import com.android.internal.protolog.ProtoLog
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
@@ -48,8 +46,8 @@
 import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT
 import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
-import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.shared.TransitionUtil
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 
@@ -65,8 +63,6 @@
     private val desktopModeEventLogger: DesktopModeEventLogger
 ) : Transitions.TransitionObserver {
 
-    private val idSequence: InstanceIdSequence by lazy { InstanceIdSequence(Int.MAX_VALUE) }
-
     init {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             shellInit.addInitCallback(this::onInit, this)
@@ -87,15 +83,7 @@
     // following enter reason could be Screen On
     private var wasPreviousTransitionExitByScreenOff: Boolean = false
 
-    // The instanceId for the current logging session
-    private var loggerInstanceId: InstanceId? = null
-
-    private val isSessionActive: Boolean
-        get() = loggerInstanceId != null
-
-    private fun setSessionInactive() {
-        loggerInstanceId = null
-    }
+    @VisibleForTesting var isSessionActive: Boolean = false
 
     fun onInit() {
         transitions.registerObserver(this)
@@ -247,38 +235,32 @@
         ) {
             // Sessions is finishing, log task updates followed by an exit event
             identifyAndLogTaskUpdates(
-                loggerInstanceId!!.id,
                 preTransitionVisibleFreeformTasks,
                 postTransitionVisibleFreeformTasks
             )
 
             desktopModeEventLogger.logSessionExit(
-                loggerInstanceId!!.id,
                 getExitReason(transitionInfo)
             )
-
-            setSessionInactive()
+            isSessionActive = false
         } else if (
             postTransitionVisibleFreeformTasks.isNotEmpty() &&
                 preTransitionVisibleFreeformTasks.isEmpty() &&
                 !isSessionActive
         ) {
             // Session is starting, log enter event followed by task updates
-            loggerInstanceId = idSequence.newInstanceId()
+            isSessionActive = true
             desktopModeEventLogger.logSessionEnter(
-                loggerInstanceId!!.id,
                 getEnterReason(transitionInfo)
             )
 
             identifyAndLogTaskUpdates(
-                loggerInstanceId!!.id,
                 preTransitionVisibleFreeformTasks,
                 postTransitionVisibleFreeformTasks
             )
         } else if (isSessionActive) {
             // Session is neither starting, nor finishing, log task updates if there are any
             identifyAndLogTaskUpdates(
-                loggerInstanceId!!.id,
                 preTransitionVisibleFreeformTasks,
                 postTransitionVisibleFreeformTasks
             )
@@ -291,7 +273,6 @@
 
     /** Compare the old and new state of taskInfos and identify and log the changes */
     private fun identifyAndLogTaskUpdates(
-        sessionId: Int,
         preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>,
         postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>
     ) {
@@ -302,7 +283,7 @@
             when {
                 // new tasks added
                 previousTaskInfo == null -> {
-                    desktopModeEventLogger.logTaskAdded(sessionId, currentTaskUpdate)
+                    desktopModeEventLogger.logTaskAdded(currentTaskUpdate)
                     Trace.setCounter(
                         Trace.TRACE_TAG_WINDOW_MANAGER,
                         VISIBLE_TASKS_COUNTER_NAME,
@@ -315,14 +296,14 @@
                 // TODO(b/347935387): Log changes only once they are stable.
                 buildTaskUpdateForTask(previousTaskInfo, postTransitionVisibleFreeformTasks.size())
                         != currentTaskUpdate ->
-                            desktopModeEventLogger.logTaskInfoChanged(sessionId, currentTaskUpdate)
+                            desktopModeEventLogger.logTaskInfoChanged(currentTaskUpdate)
             }
         }
 
         // find old tasks that were removed
         preTransitionVisibleFreeformTasks.forEach { taskId, taskInfo ->
             if (!postTransitionVisibleFreeformTasks.containsKey(taskId)) {
-                desktopModeEventLogger.logTaskRemoved(sessionId,
+                desktopModeEventLogger.logTaskRemoved(
                     buildTaskUpdateForTask(taskInfo, postTransitionVisibleFreeformTasks.size()))
                 Trace.setCounter(
                     Trace.TRACE_TAG_WINDOW_MANAGER,
@@ -417,13 +398,6 @@
         visibleFreeformTaskInfos.set(taskInfo.taskId, taskInfo)
     }
 
-    @VisibleForTesting fun getLoggerSessionId(): Int? = loggerInstanceId?.id
-
-    @VisibleForTesting
-    fun setLoggerSessionId(id: Int) {
-        loggerInstanceId = InstanceId.fakeInstanceId(id)
-    }
-
     private fun TransitionInfo.Change.requireTaskInfo(): RunningTaskInfo {
         return this.taskInfo ?: throw IllegalStateException("Expected TaskInfo in the Change")
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 52b92a8..61de077 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -378,11 +378,12 @@
 
         private static VisualIndicatorAnimator fadeBoundsIn(
                 @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) {
-            final Rect startBounds = getIndicatorBounds(displayLayout, type);
+            final Rect endBounds = getIndicatorBounds(displayLayout, type);
+            final Rect startBounds = getMinBounds(endBounds);
             view.getBackground().setBounds(startBounds);
 
             final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
-                    view, startBounds, getMaxBounds(startBounds));
+                    view, startBounds, endBounds);
             animator.setInterpolator(new DecelerateInterpolator());
             setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM);
             return animator;
@@ -390,8 +391,8 @@
 
         private static VisualIndicatorAnimator fadeBoundsOut(
                 @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) {
-            final Rect endBounds = getIndicatorBounds(displayLayout, type);
-            final Rect startBounds = getMaxBounds(endBounds);
+            final Rect startBounds = getIndicatorBounds(displayLayout, type);
+            final Rect endBounds = getMinBounds(startBounds);
             view.getBackground().setBounds(startBounds);
 
             final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
@@ -422,28 +423,35 @@
             return animator;
         }
 
+        /** Calculates the bounds the indicator should have when fully faded in. */
         private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type) {
-            final int padding = layout.stableInsets().top;
+            final Rect desktopStableBounds = new Rect();
+            layout.getStableBounds(desktopStableBounds);
+            final int padding = desktopStableBounds.top;
             switch (type) {
                 case TO_FULLSCREEN_INDICATOR:
-                    return new Rect(padding, padding,
-                            layout.width() - padding,
-                            layout.height() - padding);
+                    desktopStableBounds.top += padding;
+                    desktopStableBounds.bottom -= padding;
+                    desktopStableBounds.left += padding;
+                    desktopStableBounds.right -= padding;
+                    return desktopStableBounds;
                 case TO_DESKTOP_INDICATOR:
                     final float adjustmentPercentage = 1f
                             - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
-                    return new Rect((int) (adjustmentPercentage * layout.width() / 2),
-                            (int) (adjustmentPercentage * layout.height() / 2),
-                            (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)),
-                            (int) (layout.height() - (adjustmentPercentage * layout.height() / 2)));
+                    return new Rect((int) (adjustmentPercentage * desktopStableBounds.width() / 2),
+                            (int) (adjustmentPercentage * desktopStableBounds.height() / 2),
+                            (int) (desktopStableBounds.width()
+                                    - (adjustmentPercentage * desktopStableBounds.width() / 2)),
+                            (int) (desktopStableBounds.height()
+                                    - (adjustmentPercentage * desktopStableBounds.height() / 2)));
                 case TO_SPLIT_LEFT_INDICATOR:
                     return new Rect(padding, padding,
-                            layout.width() / 2 - padding,
-                            layout.height() - padding);
+                            desktopStableBounds.width() / 2 - padding,
+                            desktopStableBounds.height());
                 case TO_SPLIT_RIGHT_INDICATOR:
-                    return new Rect(layout.width() / 2 + padding, padding,
-                            layout.width() - padding,
-                            layout.height() - padding);
+                    return new Rect(desktopStableBounds.width() / 2 + padding, padding,
+                            desktopStableBounds.width() - padding,
+                            desktopStableBounds.height());
                 default:
                     throw new IllegalArgumentException("Invalid indicator type provided.");
             }
@@ -505,17 +513,18 @@
         }
 
         /**
-         * Return the max bounds of a visual indicator
+         * Return the minimum bounds of a visual indicator, to be used at the end of fading out
+         * and the start of fading in.
          */
-        private static Rect getMaxBounds(Rect startBounds) {
-            return new Rect((int) (startBounds.left
-                    - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.width())),
-                    (int) (startBounds.top
-                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.height())),
-                    (int) (startBounds.right
-                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.width())),
-                    (int) (startBounds.bottom
-                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.height())));
+        private static Rect getMinBounds(Rect maxBounds) {
+            return new Rect((int) (maxBounds.left
+                    + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())),
+                    (int) (maxBounds.top
+                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())),
+                    (int) (maxBounds.right
+                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())),
+                    (int) (maxBounds.bottom
+                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())));
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 57a59c9..b723337 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -659,6 +659,7 @@
         }
 
         val wct = WindowContainerTransaction()
+        if (!task.isFreeform) addMoveToDesktopChanges(wct, task, displayId)
         wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)
 
         transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
@@ -1245,7 +1246,7 @@
         val bounds = when (newTaskWindowingMode) {
             WINDOWING_MODE_FREEFORM -> {
                 displayController.getDisplayLayout(callingTask.displayId)
-                    ?.let { getInitialBounds(it, callingTask) }
+                    ?.let { getInitialBounds(it, callingTask, callingTask.displayId) }
             }
             WINDOWING_MODE_MULTI_WINDOW -> {
                 Rect()
@@ -1311,7 +1312,7 @@
             val displayLayout = displayController.getDisplayLayout(task.displayId)
             if (displayLayout != null) {
                 val initialBounds = Rect(task.configuration.windowConfiguration.bounds)
-                cascadeWindow(task, initialBounds, displayLayout)
+                cascadeWindow(initialBounds, displayLayout, task.displayId)
                 wct.setBounds(task.token, initialBounds)
             }
         }
@@ -1399,13 +1400,19 @@
         return if (wct.isEmpty) null else wct
     }
 
+    /**
+     * Apply all changes required when task is first added to desktop. Uses the task's current
+     * display by default to apply initial bounds and placement relative to the display.
+     * Use a different [displayId] if the task should be moved to a different display.
+     */
     @VisibleForTesting
     fun addMoveToDesktopChanges(
         wct: WindowContainerTransaction,
-        taskInfo: RunningTaskInfo
+        taskInfo: RunningTaskInfo,
+        displayId: Int = taskInfo.displayId,
     ) {
-        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
-        val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(taskInfo.displayId)!!
+        val displayLayout = displayController.getDisplayLayout(displayId) ?: return
+        val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)!!
         val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
         val targetWindowingMode =
             if (tdaWindowingMode == WINDOWING_MODE_FREEFORM) {
@@ -1414,7 +1421,7 @@
             } else {
                 WINDOWING_MODE_FREEFORM
             }
-        val initialBounds = getInitialBounds(displayLayout, taskInfo)
+        val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId)
 
         if (canChangeTaskPosition(taskInfo)) {
             wct.setBounds(taskInfo.token, initialBounds)
@@ -1428,7 +1435,8 @@
 
     private fun getInitialBounds(
         displayLayout: DisplayLayout,
-        taskInfo: RunningTaskInfo
+        taskInfo: RunningTaskInfo,
+        displayId: Int,
     ): Rect {
         val bounds = if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue) {
             calculateInitialBounds(displayLayout, taskInfo)
@@ -1437,7 +1445,7 @@
         }
 
         if (DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue) {
-            cascadeWindow(taskInfo, bounds, displayLayout)
+            cascadeWindow(bounds, displayLayout, displayId)
         }
         return bounds
     }
@@ -1466,11 +1474,11 @@
         }
     }
 
-    private fun cascadeWindow(task: TaskInfo, bounds: Rect, displayLayout: DisplayLayout) {
+    private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
         val stableBounds = Rect()
         displayLayout.getStableBoundsForDesktopMode(stableBounds)
 
-        val activeTasks = taskRepository.getActiveNonMinimizedOrderedTasks(task.displayId)
+        val activeTasks = taskRepository.getActiveNonMinimizedOrderedTasks(displayId)
         activeTasks.firstOrNull()?.let { activeTask ->
             shellTaskOrganizer.getRunningTaskInfo(activeTask)?.let {
                 cascadeWindow(context.resources, stableBounds,
@@ -2069,6 +2077,12 @@
                 c.removeDesktop(displayId)
             }
         }
+
+        override fun moveToExternalDisplay(taskId: Int) {
+            executeRemoteCallWithTaskPermission(controller, "moveTaskToExternalDisplay") { c ->
+                c.moveToNextDisplay(taskId)
+            }
+        }
     }
 
     private fun logV(msg: String, vararg arguments: Any?) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index 8e264b2..34c2f1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -648,7 +648,13 @@
             state.startAborted = true
             // The start-transition (DRAG_HOLD) is aborted, cancel its jank interaction.
             interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
-        } else if (state.cancelTransitionToken != transition) {
+        } else if (state.cancelTransitionToken == transition) {
+            state.draggedTaskChange?.leash?.let {
+                state.startTransitionFinishTransaction?.show(it)
+            }
+            state.startTransitionFinishCb?.onTransitionFinished(null /* wct */)
+            clearState()
+        } else {
             // This transition being aborted is neither the start, nor the cancel transition, so
             // it must be the finish transition (DRAG_RELEASE); cancel its jank interaction.
             interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE)
@@ -863,7 +869,8 @@
 
     companion object {
         /** The duration of the animation to commit or cancel the drag-to-desktop gesture. */
-        internal const val DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS = 336L
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        const val DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS = 336L
     }
 }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 86351e3..c27813d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -52,4 +52,7 @@
 
     /** Remove desktop on the given display */
     oneway void removeDesktop(int displayId);
+
+    /** Move a task with given `taskId` to external display */
+    void moveToExternalDisplay(int taskId);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 268c3a2..537ef18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -350,7 +350,7 @@
         }
         cancelPhysicsAnimation();
         mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
-        // mPipTaskOrganizer.removePip();
+        mPipScheduler.removePipAfterAnimation();
     }
 
     /** Sets the movement bounds to use to constrain PIP position animations. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index d4f190e..fbbf6f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -19,81 +19,40 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
 import android.window.WindowContainerTransaction;
 
-import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
 
 import com.android.internal.protolog.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsState;
-import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Scheduler for Shell initiated PiP transitions and animations.
  */
 public class PipScheduler {
     private static final String TAG = PipScheduler.class.getSimpleName();
-    private static final String BROADCAST_FILTER = PipScheduler.class.getCanonicalName();
 
     private final Context mContext;
     private final PipBoundsState mPipBoundsState;
     private final ShellExecutor mMainExecutor;
     private final PipTransitionState mPipTransitionState;
-    private PipSchedulerReceiver mSchedulerReceiver;
     private PipTransitionController mPipTransitionController;
+    private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+            mSurfaceControlTransactionFactory;
 
     @Nullable private Runnable mUpdateMovementBoundsRunnable;
 
-    /**
-     * Temporary PiP CUJ codes to schedule PiP related transitions directly from Shell.
-     * This is used for a broadcast receiver to resolve intents. This should be removed once
-     * there is an equivalent of PipTouchHandler and PipResizeGestureHandler for PiP2.
-     */
-    private static final int PIP_EXIT_VIA_EXPAND_CODE = 0;
-    private static final int PIP_DOUBLE_TAP = 1;
-
-    @IntDef(value = {
-            PIP_EXIT_VIA_EXPAND_CODE,
-            PIP_DOUBLE_TAP
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface PipUserJourneyCode {}
-
-    /**
-     * A temporary broadcast receiver to initiate PiP CUJs.
-     */
-    private class PipSchedulerReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            int userJourneyCode = intent.getIntExtra("cuj_code_extra", 0);
-            switch (userJourneyCode) {
-                case PIP_EXIT_VIA_EXPAND_CODE:
-                    scheduleExitPipViaExpand();
-                    break;
-                case PIP_DOUBLE_TAP:
-                    scheduleDoubleTapToResize();
-                    break;
-                default:
-                    throw new IllegalStateException("unexpected CUJ code=" + userJourneyCode);
-            }
-        }
-    }
-
     public PipScheduler(Context context,
             PipBoundsState pipBoundsState,
             ShellExecutor mainExecutor,
@@ -103,12 +62,8 @@
         mMainExecutor = mainExecutor;
         mPipTransitionState = pipTransitionState;
 
-        if (PipUtils.isPip2ExperimentEnabled()) {
-            // temporary broadcast receiver to initiate exit PiP via expand
-            mSchedulerReceiver = new PipSchedulerReceiver();
-            ContextCompat.registerReceiver(mContext, mSchedulerReceiver,
-                    new IntentFilter(BROADCAST_FILTER), ContextCompat.RECEIVER_EXPORTED);
-        }
+        mSurfaceControlTransactionFactory =
+                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
     }
 
     ShellExecutor getMainExecutor() {
@@ -133,6 +88,18 @@
         return wct;
     }
 
+    @Nullable
+    private WindowContainerTransaction getRemovePipTransaction() {
+        if (mPipTransitionState.mPipTaskToken == null) {
+            return null;
+        }
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.setBounds(mPipTransitionState.mPipTaskToken, null);
+        wct.setWindowingMode(mPipTransitionState.mPipTaskToken, WINDOWING_MODE_UNDEFINED);
+        wct.reorder(mPipTransitionState.mPipTaskToken, false);
+        return wct;
+    }
+
     /**
      * Schedules exit PiP via expand transition.
      */
@@ -146,10 +113,26 @@
         }
     }
 
-    /**
-     * Schedules resize PiP via double tap.
-     */
-    public void scheduleDoubleTapToResize() {}
+    // TODO: Optimize this by running the animation as part of the transition
+    /** Runs remove PiP animation and schedules remove PiP transition after the animation ends. */
+    public void removePipAfterAnimation() {
+        SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+        PipAlphaAnimator animator = new PipAlphaAnimator(mContext,
+                mPipTransitionState.mPinnedTaskLeash, tx, PipAlphaAnimator.FADE_OUT);
+        animator.setAnimationEndCallback(this::scheduleRemovePipImmediately);
+        animator.start();
+    }
+
+    /** Schedules remove PiP transition. */
+    private void scheduleRemovePipImmediately() {
+        WindowContainerTransaction wct = getRemovePipTransaction();
+        if (wct != null) {
+            mMainExecutor.execute(() -> {
+                mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
+                        null /* destinationBounds */);
+            });
+        }
+    }
 
     /**
      * Animates resizing of the pinned stack given the duration.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
index c58de2c..373ec80 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
@@ -90,9 +90,10 @@
         if (mPictureInPictureParams.equals(params)) {
             return;
         }
-        if (PipUtils.remoteActionsChanged(params.getActions(), mPictureInPictureParams.getActions())
+        if (params != null && (PipUtils.remoteActionsChanged(params.getActions(),
+                mPictureInPictureParams.getActions())
                 || !PipUtils.remoteActionsMatch(params.getCloseAction(),
-                mPictureInPictureParams.getCloseAction())) {
+                mPictureInPictureParams.getCloseAction()))) {
             for (PipParamsChangedCallback listener : mPipParamsChangedListeners) {
                 listener.onActionsChanged(params.getActions(), params.getCloseAction());
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 029f001..a4a7973 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -582,7 +582,6 @@
             return true;
         }
 
-        /*
         if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting())
                 && mPipDismissTargetHandler.maybeConsumeMotionEvent(ev)) {
             // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
@@ -599,6 +598,7 @@
             return true;
         }
 
+        /*
         // Ignore the motion event When the entry animation is waiting to be started
         if (!mTouchState.isUserInteracting() && mPipTaskOrganizer.isEntryScheduled()) {
             ProtoLog.wtf(WM_SHELL_PICTURE_IN_PICTURE,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index b57f51a..ac1567a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -25,6 +25,7 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_RESIZE_PIP;
 
 import android.animation.Animator;
@@ -605,8 +606,11 @@
                 && pipChange.getMode() == TRANSIT_TO_BACK;
         boolean isPipClosed = info.getType() == TRANSIT_CLOSE
                 && pipChange.getMode() == TRANSIT_CLOSE;
-        // PiP is being removed if the pinned task is either moved to back or closed.
-        return isPipMovedToBack || isPipClosed;
+        // If PiP is dismissed by user (i.e. via dismiss button in PiP menu)
+        boolean isPipDismissed = info.getType() == TRANSIT_REMOVE_PIP
+                && pipChange.getMode() == TRANSIT_TO_BACK;
+        // PiP is being removed if the pinned task is either moved to back, closed, or dismissed.
+        return isPipMovedToBack || isPipClosed || isPipDismissed;
     }
 
     //
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 47c5eec..3e76403 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -35,12 +35,19 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
 import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
+import static com.android.wm.shell.common.split.SplitScreenUtils.isPartiallyOffscreen;
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
 import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
 import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
+import static com.android.wm.shell.shared.TransitionUtil.isOrderOnly;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -117,6 +124,7 @@
 import com.android.internal.policy.FoldLockSettingsObserver;
 import com.android.internal.protolog.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
@@ -160,19 +168,19 @@
  * - The {@link SplitLayout} divider is only visible if multiple {@link StageTaskListener}s are
  * visible
  * - Both stages are put under a single-top root task.
- * This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
- * {@link #onStageHasChildrenChanged(StageListenerImpl).}
  */
 public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
         DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler,
-        ShellTaskOrganizer.TaskListener {
+        ShellTaskOrganizer.TaskListener, StageTaskListener.StageListenerCallbacks {
 
     private static final String TAG = StageCoordinator.class.getSimpleName();
 
+    // The duration in ms to prevent launch-adjacent from working after split screen is first
+    // entered
+    private static final int DISABLE_LAUNCH_ADJACENT_AFTER_ENTER_TIMEOUT_MS = 1000;
+
     private final StageTaskListener mMainStage;
-    private final StageListenerImpl mMainStageListener = new StageListenerImpl();
     private final StageTaskListener mSideStage;
-    private final StageListenerImpl mSideStageListener = new StageListenerImpl();
     @SplitPosition
     private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
 
@@ -235,6 +243,10 @@
     private SplitScreen.SplitInvocationListener mSplitInvocationListener;
     private Executor mSplitInvocationListenerExecutor;
 
+    // Re-enables launch-adjacent handling on the split root task.  This needs to be a member
+    // because we will be posting and removing it from the handler.
+    private final Runnable mReEnableLaunchAdjacentOnRoot = () -> setLaunchAdjacentDisabled(false);
+
     /**
      * Since StageCoordinator only coordinates MainStage and SideStage, it shouldn't support
      * CompatUI layouts. CompatUI is handled separately by MainStage and SideStage.
@@ -328,7 +340,7 @@
                 mContext,
                 mTaskOrganizer,
                 mDisplayId,
-                mMainStageListener,
+                this /*stageListenerCallbacks*/,
                 mSyncQueue,
                 iconProvider,
                 mWindowDecorViewModel);
@@ -336,7 +348,7 @@
                 mContext,
                 mTaskOrganizer,
                 mDisplayId,
-                mSideStageListener,
+                this /*stageListenerCallbacks*/,
                 mSyncQueue,
                 iconProvider,
                 mWindowDecorViewModel);
@@ -411,7 +423,7 @@
     }
 
     public boolean isSplitScreenVisible() {
-        return mSideStageListener.mVisible && mMainStageListener.mVisible;
+        return mSideStage.mVisible && mMainStage.mVisible;
     }
 
     private void activateSplit(WindowContainerTransaction wct, boolean includingTopTask) {
@@ -1096,7 +1108,7 @@
         mSideStagePosition = sideStagePosition;
         sendOnStagePositionChanged();
 
-        if (mSideStageListener.mVisible && updateBounds) {
+        if (mSideStage.mVisible && updateBounds) {
             if (wct == null) {
                 // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
                 onLayoutSizeChanged(mSplitLayout);
@@ -1317,8 +1329,8 @@
 
     private void clearRequestIfPresented() {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearRequestIfPresented");
-        if (mSideStageListener.mVisible && mSideStageListener.mHasChildren
-                && mMainStageListener.mVisible && mSideStageListener.mHasChildren) {
+        if (mSideStage.mVisible && mSideStage.mHasChildren
+                && mMainStage.mVisible && mSideStage.mHasChildren) {
             mSplitRequest = null;
         }
     }
@@ -1571,11 +1583,12 @@
         }
     }
 
-    private void onStageChildTaskStatusChanged(StageListenerImpl stageListener, int taskId,
+    @Override
+    public void onChildTaskStatusChanged(StageTaskListener stageListener, int taskId,
             boolean present, boolean visible) {
         int stage;
         if (present) {
-            stage = stageListener == mSideStageListener ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
+            stage = stageListener == mSideStage ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
         } else {
             // No longer on any stage
             stage = STAGE_TYPE_UNDEFINED;
@@ -1706,13 +1719,14 @@
 
 
     @VisibleForTesting
-    void onRootTaskAppeared() {
+    @Override
+    public void onRootTaskAppeared() {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskAppeared: rootTask=%s mainRoot=%b sideRoot=%b",
-                mRootTaskInfo, mMainStageListener.mHasRootTask, mSideStageListener.mHasRootTask);
+                mRootTaskInfo, mMainStage.mHasRootTask, mSideStage.mHasRootTask);
         // Wait unit all root tasks appeared.
         if (mRootTaskInfo == null
-                || !mMainStageListener.mHasRootTask
-                || !mSideStageListener.mHasRootTask) {
+                || !mMainStage.mHasRootTask
+                || !mSideStage.mHasRootTask) {
             return;
         }
 
@@ -1732,35 +1746,8 @@
         mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token);
     }
 
-    /** Callback when split roots have child task appeared under it, this is a little different from
-     * #onStageHasChildrenChanged because this would be called every time child task appeared.
-     * NOTICE: This only be called on legacy transition. */
-    private void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onChildTaskAppeared: isMainStage=%b task=%d",
-                stageListener == mMainStageListener, taskId);
-        // Handle entering split screen while there is a split pair running in the background.
-        if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive()
-                && mSplitRequest == null) {
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            prepareEnterSplitScreen(wct);
-            mMainStage.evictAllChildren(wct);
-            mSideStage.evictOtherChildren(wct, taskId);
-
-            mSyncQueue.queue(wct);
-            mSyncQueue.runInSync(t -> {
-                if (mIsDropEntering) {
-                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
-                    mIsDropEntering = false;
-                    mSkipEvictingMainStageChildren = false;
-                } else {
-                    mShowDecorImmediately = true;
-                    mSplitLayout.flingDividerToCenter(/*finishCallback*/ null);
-                }
-            });
-        }
-    }
-
-    private void onRootTaskVanished() {
+    @Override
+    public void onRootTaskVanished() {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskVanished");
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mLaunchAdjacentController.clearLaunchAdjacentRoot();
@@ -1777,15 +1764,16 @@
 
     /** Callback when split roots visiblility changed.
      * NOTICE: This only be called on legacy transition. */
-    private void onStageVisibilityChanged(StageListenerImpl stageListener) {
+    @Override
+    public void onStageVisibilityChanged(StageTaskListener stageListener) {
         // If split didn't active, just ignore this callback because we should already did these
         // on #applyExitSplitScreen.
         if (!isSplitActive()) {
             return;
         }
 
-        final boolean sideStageVisible = mSideStageListener.mVisible;
-        final boolean mainStageVisible = mMainStageListener.mVisible;
+        final boolean sideStageVisible = mSideStage.mVisible;
+        final boolean mainStageVisible = mMainStage.mVisible;
 
         // Wait for both stages having the same visibility to prevent causing flicker.
         if (mainStageVisible != sideStageVisible) {
@@ -1922,18 +1910,19 @@
 
     /** Callback when split roots have child or haven't under it.
      * NOTICE: This only be called on legacy transition. */
-    private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
+    @Override
+    public void onStageHasChildrenChanged(StageTaskListener stageListener) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onStageHasChildrenChanged: isMainStage=%b",
-                stageListener == mMainStageListener);
+                stageListener == mMainStage);
         final boolean hasChildren = stageListener.mHasChildren;
-        final boolean isSideStage = stageListener == mSideStageListener;
+        final boolean isSideStage = stageListener == mSideStage;
         if (!hasChildren && !mIsExiting && isSplitActive()) {
-            if (isSideStage && mMainStageListener.mVisible) {
+            if (isSideStage && mMainStage.mVisible) {
                 // Exit to main stage if side stage no longer has children.
                 mSplitLayout.flingDividerToDismiss(
                         mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT,
                         EXIT_REASON_APP_FINISHED);
-            } else if (!isSideStage && mSideStageListener.mVisible) {
+            } else if (!isSideStage && mSideStage.mVisible) {
                 // Exit to side stage if main stage no longer has children.
                 mSplitLayout.flingDividerToDismiss(
                         mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT,
@@ -1958,7 +1947,7 @@
                 }
             });
         }
-        if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
+        if (mMainStage.mHasChildren && mSideStage.mHasChildren) {
             mShouldUpdateRecents = true;
             clearRequestIfPresented();
             updateRecentTasksSplitPair();
@@ -1974,6 +1963,35 @@
     }
 
     @Override
+    public void onNoLongerSupportMultiWindow(StageTaskListener stageTaskListener,
+            ActivityManager.RunningTaskInfo taskInfo) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onNoLongerSupportMultiWindow: task=%s", taskInfo);
+        if (isSplitActive()) {
+            final boolean isMainStage = mMainStage == stageTaskListener;
+
+            // If visible, we preserve the app and keep it running. If an app becomes
+            // unsupported in the bg, break split without putting anything on top
+            boolean splitScreenVisible = isSplitScreenVisible();
+            int stageType = STAGE_TYPE_UNDEFINED;
+            if (splitScreenVisible) {
+                stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+            }
+            final WindowContainerTransaction wct = new WindowContainerTransaction();
+            prepareExitSplitScreen(stageType, wct);
+            clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+            mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
+                    EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+            Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow",
+                    "app package " + taskInfo.baseIntent.getComponent()
+                            + " does not support splitscreen, or is a controlled activity"
+                            + " type"));
+            if (splitScreenVisible) {
+                handleUnsupportedSplitStart();
+            }
+        }
+    }
+
+    @Override
     public void onSnappedToDismiss(boolean bottomOrRight, @ExitReason int exitReason) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onSnappedToDismiss: bottomOrRight=%b reason=%s",
                 bottomOrRight, exitReasonToString(exitReason));
@@ -2045,6 +2063,13 @@
             mSplitLayout.setDividerInteractive(true, false, "onSplitResizeFinish");
         }, mMainStage.getSplitDecorManager(), mSideStage.getSplitDecorManager());
 
+        if (Flags.enableFlexibleTwoAppSplit()) {
+            switch (layout.calculateCurrentSnapPosition()) {
+                case SNAP_TO_2_10_90 -> grantFocusToPosition(false /* leftOrTop */);
+                case SNAP_TO_2_90_10 -> grantFocusToPosition(true /* leftOrTop */);
+            }
+        }
+
         mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
     }
 
@@ -2498,6 +2523,26 @@
                         mTaskOrganizer.applyTransaction(wct);
                     }
                     continue;
+                } else if (Flags.enableFlexibleTwoAppSplit() && isOrderOnly(change)) {
+                    int focusedStageIndex = SPLIT_INDEX_UNDEFINED;
+                    if (taskInfo.token.equals(mMainStage.mRootTaskInfo.token)) {
+                        focusedStageIndex = mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+                                ? SPLIT_INDEX_0 : SPLIT_INDEX_1;
+                    } else if (taskInfo.token.equals(mSideStage.mRootTaskInfo.token)) {
+                        focusedStageIndex = mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+                                ? SPLIT_INDEX_1 : SPLIT_INDEX_0;
+                    }
+
+                    if (focusedStageIndex != SPLIT_INDEX_UNDEFINED) {
+                        @PersistentSnapPosition int currentSnapPosition =
+                                mSplitLayout.calculateCurrentSnapPosition();
+                        boolean offscreenTaskFocused =
+                                isPartiallyOffscreen(focusedStageIndex, currentSnapPosition);
+
+                        if (offscreenTaskFocused) {
+                            mSplitLayout.flingDividerToOtherSide(currentSnapPosition);
+                        }
+                    }
                 }
                 final StageTaskListener stage = getStageOfTask(taskInfo);
                 if (stage == null) {
@@ -2662,6 +2707,16 @@
         }
     }
 
+    /**
+     * Sets whether launch-adjacent is disabled or enabled.
+     */
+    private void setLaunchAdjacentDisabled(boolean disabled) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setLaunchAdjacentDisabled: disabled=%b", disabled);
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.setDisableLaunchAdjacent(mRootTaskInfo.token, disabled);
+        mTaskOrganizer.applyTransaction(wct);
+    }
+
     /** Starts the pending transition animation. */
     public boolean startPendingAnimation(@NonNull IBinder transition,
             @NonNull TransitionInfo info,
@@ -2674,6 +2729,14 @@
         if (mSplitTransitions.isPendingEnter(transition)) {
             shouldAnimate = startPendingEnterAnimation(transition,
                     mSplitTransitions.mPendingEnter, info, startTransaction, finishTransaction);
+
+            // Disable launch adjacent after an enter animation to prevent cases where apps are
+            // incorrectly trampolining and incorrectly triggering a double launch-adjacent task
+            // launch (ie. main -> split -> main). See b/344216031
+            setLaunchAdjacentDisabled(true);
+            mMainHandler.removeCallbacks(mReEnableLaunchAdjacentOnRoot);
+            mMainHandler.postDelayed(mReEnableLaunchAdjacentOnRoot,
+                    DISABLE_LAUNCH_ADJACENT_AFTER_ENTER_TIMEOUT_MS);
         } else if (mSplitTransitions.isPendingDismiss(transition)) {
             final SplitScreenTransitions.DismissSession dismiss = mSplitTransitions.mPendingDismiss;
             shouldAnimate = startPendingDismissAnimation(
@@ -3182,13 +3245,9 @@
         pw.println(childPrefix + "stagePosition=" + splitPositionToString(getMainStagePosition()));
         pw.println(childPrefix + "isActive=" + isSplitActive());
         mMainStage.dump(pw, childPrefix);
-        pw.println(innerPrefix + "MainStageListener");
-        mMainStageListener.dump(pw, childPrefix);
         pw.println(innerPrefix + "SideStage");
         pw.println(childPrefix + "stagePosition=" + splitPositionToString(getSideStagePosition()));
         mSideStage.dump(pw, childPrefix);
-        pw.println(innerPrefix + "SideStageListener");
-        mSideStageListener.dump(pw, childPrefix);
         if (mSplitLayout != null) {
             mSplitLayout.dump(pw, childPrefix);
         }
@@ -3204,8 +3263,8 @@
      */
     private void setSplitsVisible(boolean visible) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setSplitsVisible: visible=%b", visible);
-        mMainStageListener.mVisible = mSideStageListener.mVisible = visible;
-        mMainStageListener.mHasChildren = mSideStageListener.mHasChildren = visible;
+        mMainStage.mVisible = mSideStage.mVisible = visible;
+        mMainStage.mHasChildren = mSideStage.mHasChildren = visible;
     }
 
     /**
@@ -3255,86 +3314,4 @@
                 !toMainStage ? mSideStage.getTopChildTaskUid() : 0 /* sideStageUid */,
                 mSplitLayout.isLeftRightSplit());
     }
-
-    class StageListenerImpl implements StageTaskListener.StageListenerCallbacks {
-        boolean mHasRootTask = false;
-        boolean mVisible = false;
-        boolean mHasChildren = false;
-
-        @Override
-        public void onRootTaskAppeared() {
-            mHasRootTask = true;
-            StageCoordinator.this.onRootTaskAppeared();
-        }
-
-        @Override
-        public void onChildTaskAppeared(int taskId) {
-            StageCoordinator.this.onChildTaskAppeared(this, taskId);
-        }
-
-        @Override
-        public void onStatusChanged(boolean visible, boolean hasChildren) {
-            if (!mHasRootTask) return;
-
-            if (mHasChildren != hasChildren) {
-                mHasChildren = hasChildren;
-                StageCoordinator.this.onStageHasChildrenChanged(this);
-            }
-            if (mVisible != visible) {
-                mVisible = visible;
-                StageCoordinator.this.onStageVisibilityChanged(this);
-            }
-        }
-
-        @Override
-        public void onChildTaskStatusChanged(int taskId, boolean present, boolean visible) {
-            StageCoordinator.this.onStageChildTaskStatusChanged(this, taskId, present, visible);
-        }
-
-        @Override
-        public void onRootTaskVanished() {
-            reset();
-            StageCoordinator.this.onRootTaskVanished();
-        }
-
-        @Override
-        public void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo) {
-            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onNoLongerSupportMultiWindow: task=%s", taskInfo);
-            if (isSplitActive()) {
-                final boolean isMainStage = mMainStageListener == this;
-
-                // If visible, we preserve the app and keep it running. If an app becomes
-                // unsupported in the bg, break split without putting anything on top
-                boolean splitScreenVisible = isSplitScreenVisible();
-                int stageType = STAGE_TYPE_UNDEFINED;
-                if (splitScreenVisible) {
-                    stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
-                }
-                final WindowContainerTransaction wct = new WindowContainerTransaction();
-                prepareExitSplitScreen(stageType, wct);
-                clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
-                mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
-                        EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
-                Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow",
-                        "app package " + taskInfo.baseIntent.getComponent()
-                                + " does not support splitscreen, or is a controlled activity"
-                                + " type"));
-                if (splitScreenVisible) {
-                    handleUnsupportedSplitStart();
-                }
-            }
-        }
-
-        private void reset() {
-            mHasRootTask = false;
-            mVisible = false;
-            mHasChildren = false;
-        }
-
-        public void dump(@NonNull PrintWriter pw, String prefix) {
-            pw.println(prefix + "mHasRootTask=" + mHasRootTask);
-            pw.println(prefix + "mVisible=" + mVisible);
-            pw.println(prefix + "mHasChildren=" + mHasChildren);
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index d64c0a2..ae4bd16 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -22,20 +22,17 @@
 import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
-import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
 
 import android.annotation.CallSuper;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
@@ -74,20 +71,21 @@
     // No current way to enforce this but if enableFlexibleSplit() is enabled, then only 1 of the
     // stages should have this be set/being used
     private boolean mIsActive;
-
     /** Callback interface for listening to changes in a split-screen stage. */
     public interface StageListenerCallbacks {
         void onRootTaskAppeared();
 
-        void onChildTaskAppeared(int taskId);
+        void onStageHasChildrenChanged(StageTaskListener stageTaskListener);
 
-        void onStatusChanged(boolean visible, boolean hasChildren);
+        void onStageVisibilityChanged(StageTaskListener stageTaskListener);
 
-        void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
+        void onChildTaskStatusChanged(StageTaskListener stage, int taskId, boolean present,
+                boolean visible);
 
         void onRootTaskVanished();
 
-        void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo);
+        void onNoLongerSupportMultiWindow(StageTaskListener stageTaskListener,
+                ActivityManager.RunningTaskInfo taskInfo);
     }
 
     private final Context mContext;
@@ -96,6 +94,12 @@
     private final IconProvider mIconProvider;
     private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
 
+    /** Whether or not the root task has been created. */
+    boolean mHasRootTask = false;
+    /** Whether or not the root task is visible. */
+    boolean mVisible = false;
+    /** Whether or not the root task has any children or not. */
+    boolean mHasChildren = false;
     protected ActivityManager.RunningTaskInfo mRootTaskInfo;
     protected SurfaceControl mRootLeash;
     protected SurfaceControl mDimLayer;
@@ -201,6 +205,7 @@
             mSplitDecorManager = new SplitDecorManager(
                     mRootTaskInfo.configuration,
                     mIconProvider);
+            mHasRootTask = true;
             mCallbacks.onRootTaskAppeared();
             sendStatusChanged();
             mSyncQueue.runInSync(t -> mDimLayer =
@@ -209,15 +214,8 @@
             final int taskId = taskInfo.taskId;
             mChildrenLeashes.put(taskId, leash);
             mChildrenTaskInfo.put(taskId, taskInfo);
-            mCallbacks.onChildTaskStatusChanged(taskId, true /* present */,
+            mCallbacks.onChildTaskStatusChanged(this, taskId, true /* present */,
                     taskInfo.isVisible && taskInfo.isVisibleRequested);
-            if (ENABLE_SHELL_TRANSITIONS) {
-                // Status is managed/synchronized by the transition lifecycle.
-                return;
-            }
-            updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
-            mCallbacks.onChildTaskAppeared(taskId);
-            sendStatusChanged();
         } else {
             throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
                     + "\n mRootTaskInfo: " + mRootTaskInfo);
@@ -231,14 +229,6 @@
                 taskInfo.taskId, taskInfo.baseActivity);
         mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
         if (mRootTaskInfo.taskId == taskInfo.taskId) {
-            // Inflates split decor view only when the root task is visible.
-            if (!ENABLE_SHELL_TRANSITIONS && mRootTaskInfo.isVisible != taskInfo.isVisible) {
-                if (taskInfo.isVisible) {
-                    mSplitDecorManager.inflate(mContext, mRootLeash);
-                } else {
-                    mSyncQueue.runInSync(t -> mSplitDecorManager.release(t));
-                }
-            }
             mRootTaskInfo = taskInfo;
         } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
             if (!taskInfo.supportsMultiWindow
@@ -250,25 +240,16 @@
                         taskInfo.taskId);
                 // Leave split screen if the task no longer supports multi window or have
                 // uncontrolled task.
-                mCallbacks.onNoLongerSupportMultiWindow(taskInfo);
+                mCallbacks.onNoLongerSupportMultiWindow(this, taskInfo);
                 return;
             }
             mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
-            mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
+            mCallbacks.onChildTaskStatusChanged(this, taskInfo.taskId, true /* present */,
                     taskInfo.isVisible && taskInfo.isVisibleRequested);
-            if (!ENABLE_SHELL_TRANSITIONS) {
-                updateChildTaskSurface(
-                        taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
-            }
         } else {
             throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
                     + "\n mRootTaskInfo: " + mRootTaskInfo);
         }
-        if (ENABLE_SHELL_TRANSITIONS) {
-            // Status is managed/synchronized by the transition lifecycle.
-            return;
-        }
-        sendStatusChanged();
     }
 
     @Override
@@ -278,6 +259,9 @@
         final int taskId = taskInfo.taskId;
         mWindowDecorViewModel.ifPresent(vm -> vm.onTaskVanished(taskInfo));
         if (mRootTaskInfo.taskId == taskId) {
+            mHasRootTask = false;
+            mVisible = false;
+            mHasChildren = false;
             mCallbacks.onRootTaskVanished();
             mRootTaskInfo = null;
             mRootLeash = null;
@@ -288,12 +272,8 @@
         } else if (mChildrenTaskInfo.contains(taskId)) {
             mChildrenTaskInfo.remove(taskId);
             mChildrenLeashes.remove(taskId);
-            mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
-            if (ENABLE_SHELL_TRANSITIONS) {
-                // Status is managed/synchronized by the transition lifecycle.
-                return;
-            }
-            sendStatusChanged();
+            mCallbacks.onChildTaskStatusChanged(this, taskId, false /* present */,
+                    taskInfo.isVisible);
         } else {
             throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
                     + "\n mRootTaskInfo: " + mRootTaskInfo);
@@ -455,26 +435,6 @@
         }
     }
 
-    private void updateChildTaskSurface(ActivityManager.RunningTaskInfo taskInfo,
-            SurfaceControl leash, boolean firstAppeared) {
-        final Point taskPositionInParent = taskInfo.positionInParent;
-        mSyncQueue.runInSync(t -> {
-            // The task surface might be released before running in the sync queue for the case like
-            // trampoline launch, so check if the surface is valid before processing it.
-            if (!leash.isValid()) {
-                Slog.w(TAG, "Skip updating invalid child task surface of task#" + taskInfo.taskId);
-                return;
-            }
-            t.setCrop(leash, null);
-            t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
-            if (firstAppeared) {
-                t.setAlpha(leash, 1f);
-                t.setMatrix(leash, 1, 0, 0, 1);
-                t.show(leash);
-            }
-        });
-    }
-
     // ---------
     // Previously only used in MainStage
     boolean isActive() {
@@ -538,7 +498,19 @@
     }
 
     private void sendStatusChanged() {
-        mCallbacks.onStatusChanged(mRootTaskInfo.isVisible, mChildrenTaskInfo.size() > 0);
+        boolean hasChildren = mChildrenTaskInfo.size() > 0;
+        boolean visible = mRootTaskInfo.isVisible;
+        if (!mHasRootTask) return;
+
+        if (mHasChildren != hasChildren) {
+            mHasChildren = hasChildren;
+            mCallbacks.onStageHasChildrenChanged(this);
+        }
+
+        if (mVisible != visible) {
+            mVisible = visible;
+            mCallbacks.onStageVisibilityChanged(this);
+        }
     }
 
     @Override
@@ -554,5 +526,8 @@
                         + " baseActivity=" + taskInfo.baseActivity);
             }
         }
+        pw.println(prefix + "mHasRootTask=" + mHasRootTask);
+        pw.println(prefix + "mVisible=" + mVisible);
+        pw.println(prefix + "mHasChildren=" + mHasChildren);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index a2439a9..5437167 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -61,6 +61,7 @@
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+import static com.android.wm.shell.transition.DefaultSurfaceAnimator.buildSurfaceAnimation;
 import static com.android.wm.shell.transition.TransitionAnimationHelper.edgeExtendWindow;
 import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
 import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionTypeFromInfo;
@@ -68,8 +69,6 @@
 import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -81,7 +80,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Color;
-import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -90,12 +88,10 @@
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.util.ArrayMap;
-import android.view.Choreographer;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
-import android.view.animation.Transformation;
 import android.window.TransitionInfo;
 import android.window.TransitionMetrics;
 import android.window.TransitionRequestInfo;
@@ -362,7 +358,6 @@
                     isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
                     if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
                         final int flags = wallpaperTransit != WALLPAPER_TRANSITION_NONE
-                                && Flags.commonSurfaceAnimator()
                                 ? ScreenRotationAnimation.FLAG_HAS_WALLPAPER : 0;
                         startRotationAnimation(startTransaction, change, info, anim, flags,
                                 animations, onAnimFinish);
@@ -823,72 +818,6 @@
         return a;
     }
 
-    /** Builds an animator for the surface and adds it to the `animations` list. */
-    static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations,
-            @NonNull Animation anim, @NonNull SurfaceControl leash,
-            @NonNull Runnable finishCallback, @NonNull TransactionPool pool,
-            @NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
-            @Nullable Rect clipRect, boolean isActivity) {
-        if (Flags.commonSurfaceAnimator()) {
-            DefaultSurfaceAnimator.buildSurfaceAnimation(animations, anim, leash, finishCallback,
-                    pool, mainExecutor, position, cornerRadius, clipRect, isActivity);
-            return;
-        }
-        final SurfaceControl.Transaction transaction = pool.acquire();
-        final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-        final Transformation transformation = new Transformation();
-        final float[] matrix = new float[9];
-        // Animation length is already expected to be scaled.
-        va.overrideDurationScale(1.0f);
-        va.setDuration(anim.computeDurationHint());
-        final ValueAnimator.AnimatorUpdateListener updateListener = animation -> {
-            final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
-
-            applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
-                    position, cornerRadius, clipRect, isActivity);
-        };
-        va.addUpdateListener(updateListener);
-
-        final Runnable finisher = () -> {
-            applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
-                    position, cornerRadius, clipRect, isActivity);
-
-            pool.release(transaction);
-            mainExecutor.execute(() -> {
-                animations.remove(va);
-                finishCallback.run();
-            });
-        };
-        va.addListener(new AnimatorListenerAdapter() {
-            // It is possible for the end/cancel to be called more than once, which may cause
-            // issues if the animating surface has already been released. Track the finished
-            // state here to skip duplicate callbacks. See b/252872225.
-            private boolean mFinished = false;
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                onFinish();
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                onFinish();
-            }
-
-            private void onFinish() {
-                if (mFinished) return;
-                mFinished = true;
-                finisher.run();
-                // The update listener can continue to be called after the animation has ended if
-                // end() is called manually again before the finisher removes the animation.
-                // Remove it manually here to prevent animating a released surface.
-                // See b/252872225.
-                va.removeUpdateListener(updateListener);
-            }
-        });
-        animations.add(va);
-    }
-
     private void attachThumbnail(@NonNull ArrayList<Animator> animations,
             @NonNull Runnable finishCallback, TransitionInfo.Change change,
             TransitionInfo.AnimationOptions options, float cornerRadius) {
@@ -1014,38 +943,4 @@
                 || animType == ANIM_CLIP_REVEAL || animType == ANIM_OPEN_CROSS_PROFILE_APPS
                 || animType == ANIM_FROM_STYLE;
     }
-
-    private static void applyTransformation(long time, SurfaceControl.Transaction t,
-            SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
-            Point position, float cornerRadius, @Nullable Rect immutableClipRect,
-            boolean isActivity) {
-        tmpTransformation.clear();
-        anim.getTransformation(time, tmpTransformation);
-        if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
-                && anim.getExtensionEdges() != 0x0 && isActivity) {
-            t.setEdgeExtensionEffect(leash, anim.getExtensionEdges());
-        }
-        if (position != null) {
-            tmpTransformation.getMatrix().postTranslate(position.x, position.y);
-        }
-        t.setMatrix(leash, tmpTransformation.getMatrix(), matrix);
-        t.setAlpha(leash, tmpTransformation.getAlpha());
-
-        final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect);
-        Insets extensionInsets = Insets.min(tmpTransformation.getInsets(), Insets.NONE);
-        if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
-            // Clip out any overflowing edge extension
-            clipRect.inset(extensionInsets);
-            t.setCrop(leash, clipRect);
-        }
-
-        if (anim.hasRoundedCorners() && cornerRadius > 0 && clipRect != null) {
-            // We can only apply rounded corner if a crop is set
-            t.setCrop(leash, clipRect);
-            t.setCornerRadius(leash, cornerRadius);
-        }
-
-        t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
-        t.apply();
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 1a04997..6f3aa11 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -21,7 +21,7 @@
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
 import static android.view.WindowManagerPolicyConstants.SCREEN_FREEZE_LAYER_BASE;
 
-import static com.android.wm.shell.transition.DefaultTransitionHandler.buildSurfaceAnimation;
+import static com.android.wm.shell.transition.DefaultSurfaceAnimator.buildSurfaceAnimation;
 import static com.android.wm.shell.transition.Transitions.TAG;
 
 import android.animation.Animator;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 2c621b1f..d3b7ca1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -514,8 +514,12 @@
             ));
         } else {
             mWindowDecorViewHolder.bindData(new AppHeaderViewHolder.HeaderData(
-                    mTaskInfo, TaskInfoKt.getRequestingImmersive(mTaskInfo), inFullImmersive,
-                    hasGlobalFocus
+                    mTaskInfo,
+                    TaskInfoKt.getRequestingImmersive(mTaskInfo),
+                    inFullImmersive,
+                    hasGlobalFocus,
+                    /* maximizeHoverEnabled= */ canOpenMaximizeMenu(
+                            /* animatingTaskResizeOrReposition= */ false)
             ));
         }
         Trace.endSection();
@@ -1616,8 +1620,14 @@
 
     void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) {
         if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return;
-        asAppHeader(mWindowDecorViewHolder)
-                .setAnimatingTaskResizeOrReposition(animatingTaskResizeOrReposition);
+        final boolean inFullImmersive =
+                mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId);
+        asAppHeader(mWindowDecorViewHolder).bindData(new AppHeaderViewHolder.HeaderData(
+                mTaskInfo,
+                TaskInfoKt.getRequestingImmersive(mTaskInfo),
+                inFullImmersive,
+                isFocused(),
+                /* maximizeHoverEnabled= */ canOpenMaximizeMenu(animatingTaskResizeOrReposition)));
     }
 
     /**
@@ -1634,6 +1644,16 @@
         asAppHeader(mWindowDecorViewHolder).onMaximizeWindowHoverEnter();
     }
 
+    private boolean canOpenMaximizeMenu(boolean animatingTaskResizeOrReposition) {
+        if (!Flags.enableFullyImmersiveInDesktop()) {
+            return !animatingTaskResizeOrReposition;
+        }
+        final boolean inImmersiveAndRequesting =
+                mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId)
+                        && TaskInfoKt.getRequestingImmersive(mTaskInfo);
+        return !animatingTaskResizeOrReposition && !inImmersiveAndRequesting;
+    }
+
     @Override
     public String toString() {
         return "{"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index cf03b3f..d943918 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -70,7 +70,7 @@
         rootView: View,
         onCaptionTouchListener: View.OnTouchListener,
         onCaptionButtonClickListener: View.OnClickListener,
-        onLongClickListener: OnLongClickListener,
+        private val onLongClickListener: OnLongClickListener,
         onCaptionGenericMotionListener: View.OnGenericMotionListener,
         appName: CharSequence,
         appIconBitmap: Bitmap,
@@ -81,7 +81,8 @@
         val taskInfo: RunningTaskInfo,
         val isRequestingImmersive: Boolean,
         val inFullImmersiveState: Boolean,
-        val hasGlobalFocus: Boolean
+        val hasGlobalFocus: Boolean,
+        val enableMaximizeLongClick: Boolean,
     ) : Data()
 
     private val decorThemeUtil = DecorThemeUtil(context)
@@ -160,19 +161,30 @@
     }
 
     override fun bindData(data: HeaderData) {
-        bindData(data.taskInfo, data.isRequestingImmersive, data.inFullImmersiveState,
-            data.hasGlobalFocus)
+        bindData(
+            data.taskInfo,
+            data.isRequestingImmersive,
+            data.inFullImmersiveState,
+            data.hasGlobalFocus,
+            data.enableMaximizeLongClick
+        )
     }
 
     private fun bindData(
         taskInfo: RunningTaskInfo,
         isRequestingImmersive: Boolean,
         inFullImmersiveState: Boolean,
-        hasGlobalFocus: Boolean
+        hasGlobalFocus: Boolean,
+        enableMaximizeLongClick: Boolean,
     ) {
         if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
-            bindDataWithThemedHeaders(taskInfo, isRequestingImmersive, inFullImmersiveState,
-                hasGlobalFocus)
+            bindDataWithThemedHeaders(
+                taskInfo,
+                isRequestingImmersive,
+                inFullImmersiveState,
+                hasGlobalFocus,
+                enableMaximizeLongClick,
+            )
         } else {
             bindDataLegacy(taskInfo, hasGlobalFocus)
         }
@@ -215,7 +227,8 @@
         taskInfo: RunningTaskInfo,
         requestingImmersive: Boolean,
         inFullImmersiveState: Boolean,
-        hasGlobalFocus: Boolean
+        hasGlobalFocus: Boolean,
+        enableMaximizeLongClick: Boolean,
     ) {
         val header = fillHeaderInfo(taskInfo, hasGlobalFocus)
         val headerStyle = getHeaderStyle(header)
@@ -281,6 +294,16 @@
                 drawableInsets = closeDrawableInsets
             )
         }
+        if (!enableMaximizeLongClick) {
+            maximizeButtonView.cancelHoverAnimation()
+        }
+        maximizeButtonView.hoverDisabled = !enableMaximizeLongClick
+        maximizeWindowButton.onLongClickListener = if (enableMaximizeLongClick) {
+            onLongClickListener
+        } else {
+            // Disable long-click to open maximize menu when in immersive.
+            null
+        }
     }
 
     override fun onHandleMenuOpened() {}
@@ -291,14 +314,6 @@
         }
     }
 
-    fun setAnimatingTaskResizeOrReposition(animatingTaskResizeOrReposition: Boolean) {
-        // If animating a task resize or reposition, cancel any running hover animations
-        if (animatingTaskResizeOrReposition) {
-            maximizeButtonView.cancelHoverAnimation()
-        }
-        maximizeButtonView.hoverDisabled = animatingTaskResizeOrReposition
-    }
-
     fun onMaximizeWindowHoverExit() {
         maximizeButtonView.cancelHoverAnimation()
     }
@@ -364,6 +379,11 @@
     private fun shouldShowExitFullImmersiveIcon(
         requestingImmersive: Boolean,
         inFullImmersiveState: Boolean
+    ): Boolean = isInFullImmersiveStateAndRequesting(requestingImmersive, inFullImmersiveState)
+
+    private fun isInFullImmersiveStateAndRequesting(
+        requestingImmersive: Boolean,
+        inFullImmersiveState: Boolean
     ): Boolean = Flags.enableFullyImmersiveInDesktop()
             && requestingImmersive && inFullImmersiveState
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
index 1da4ef6..266e484 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
@@ -53,6 +53,7 @@
         return new BackMotionEvent(
                 /* touchX = */ touchX,
                 /* touchY = */ 0,
+                /* frameTime = */ 0,
                 /* progress = */ progress,
                 /* triggerBack = */ false,
                 /* swipeEdge = */ BackEvent.EDGE_LEFT,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
index 2235c20..2cc52c5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
@@ -221,6 +221,7 @@
         BackMotionEvent(
             /* touchX = */ touchX,
             /* touchY = */ 0f,
+            /* frameTime = */ 0,
             /* progress = */ progress,
             /* triggerBack = */ false,
             /* swipeEdge = */ BackEvent.EDGE_LEFT,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
index dde9fda..0825b6b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
@@ -18,7 +18,10 @@
 
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
+import com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations
+import com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker
 import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
+import com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions
 import com.android.internal.util.FrameworkStatsLog
 import com.android.modules.utils.testing.ExtendedMockitoRule
 import com.android.window.flags.Flags
@@ -26,15 +29,16 @@
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.NO_SESSION_ID
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskSizeUpdate
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_MINIMIZE_REASON
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_UNMINIMIZE_REASON
-import kotlinx.coroutines.runBlocking
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
+import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.mockito.kotlin.eq
@@ -49,40 +53,87 @@
     @JvmField
     @Rule(order = 0)
     val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
-            .mockStatic(FrameworkStatsLog::class.java)
-            .mockStatic(EventLogTags::class.java).build()!!
+        .mockStatic(FrameworkStatsLog::class.java)
+        .mockStatic(EventLogTags::class.java).build()!!
 
     @JvmField
     @Rule(order = 1)
     val setFlagsRule = SetFlagsRule()
 
     @Test
-    fun logSessionEnter_enterReason() = runBlocking {
-        desktopModeEventLogger.logSessionEnter(sessionId = SESSION_ID, EnterReason.UNKNOWN_ENTER)
+    fun logSessionEnter_logsEnterReasonWithNewSessionId() {
+        desktopModeEventLogger.logSessionEnter(EnterReason.KEYBOARD_SHORTCUT_ENTER)
 
+        val sessionId = desktopModeEventLogger.currentSessionId.get()
+        assertThat(sessionId).isNotEqualTo(NO_SESSION_ID)
         verify {
             FrameworkStatsLog.write(
                 eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
                 /* event */
                 eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER),
                 /* enter_reason */
-                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER),
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER),
                 /* exit_reason */
                 eq(0),
                 /* sessionId */
-                eq(SESSION_ID)
+                eq(sessionId)
             )
         }
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellEnterDesktopMode(
-                eq(EnterReason.UNKNOWN_ENTER.reason),
-                eq(SESSION_ID))
+                eq(EnterReason.KEYBOARD_SHORTCUT_ENTER.reason),
+                eq(sessionId)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
-    fun logSessionExit_exitReason() = runBlocking {
-        desktopModeEventLogger.logSessionExit(sessionId = SESSION_ID, ExitReason.UNKNOWN_EXIT)
+    fun logSessionEnter_ongoingSession_logsEnterReasonWithNewSessionId() {
+        val previousSessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logSessionEnter(EnterReason.KEYBOARD_SHORTCUT_ENTER)
+
+        val sessionId = desktopModeEventLogger.currentSessionId.get()
+        assertThat(sessionId).isNotEqualTo(NO_SESSION_ID)
+        assertThat(sessionId).isNotEqualTo(previousSessionId)
+        verify {
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
+                /* event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER),
+                /* enter_reason */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER),
+                /* exit_reason */
+                eq(0),
+                /* sessionId */
+                eq(sessionId)
+            )
+        }
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verify {
+            EventLogTags.writeWmShellEnterDesktopMode(
+                eq(EnterReason.KEYBOARD_SHORTCUT_ENTER.reason),
+                eq(sessionId)
+            )
+        }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+    }
+
+    @Test
+    fun logSessionExit_noOngoingSession_doesNotLog() {
+        desktopModeEventLogger.logSessionExit(ExitReason.DRAG_TO_EXIT)
+
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+    }
+
+    @Test
+    fun logSessionExit_logsExitReasonAndClearsSessionId() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logSessionExit(ExitReason.DRAG_TO_EXIT)
 
         verify {
             FrameworkStatsLog.write(
@@ -92,24 +143,39 @@
                 /* enter_reason */
                 eq(0),
                 /* exit_reason */
-                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT),
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__DRAG_TO_EXIT),
                 /* sessionId */
-                eq(SESSION_ID)
+                eq(sessionId)
             )
         }
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellExitDesktopMode(
-                eq(ExitReason.UNKNOWN_EXIT.reason),
-                eq(SESSION_ID))
+                eq(ExitReason.DRAG_TO_EXIT.reason),
+                eq(sessionId)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+        assertThat(desktopModeEventLogger.currentSessionId.get()).isEqualTo(NO_SESSION_ID)
     }
 
     @Test
-    fun logTaskAdded_taskUpdate() = runBlocking {
-        desktopModeEventLogger.logTaskAdded(sessionId = SESSION_ID, TASK_UPDATE)
+    fun logTaskAdded_noOngoingSession_doesNotLog() {
+        desktopModeEventLogger.logTaskAdded(TASK_UPDATE)
+
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+    }
+
+    @Test
+    fun logTaskAdded_logsTaskUpdate() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskAdded(TASK_UPDATE)
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                 /* task_event */
                 eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED),
                 /* instance_id */
@@ -125,36 +191,52 @@
                 /* task_y */
                 eq(TASK_UPDATE.taskY),
                 /* session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UNSET_UNMINIMIZE_REASON),
                 /* visible_task_count */
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
-
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellDesktopModeTaskUpdate(
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED
+                ),
                 eq(TASK_UPDATE.instanceId),
                 eq(TASK_UPDATE.uid),
                 eq(TASK_UPDATE.taskHeight),
                 eq(TASK_UPDATE.taskWidth),
                 eq(TASK_UPDATE.taskX),
                 eq(TASK_UPDATE.taskY),
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UNSET_UNMINIMIZE_REASON),
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
-    fun logTaskRemoved_taskUpdate() = runBlocking {
-        desktopModeEventLogger.logTaskRemoved(sessionId = SESSION_ID, TASK_UPDATE)
+    fun logTaskRemoved_noOngoingSession_doesNotLog() {
+        desktopModeEventLogger.logTaskRemoved(TASK_UPDATE)
+
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+    }
+
+    @Test
+    fun logTaskRemoved_taskUpdate() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskRemoved(TASK_UPDATE)
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                 /* task_event */
                 eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED),
                 /* instance_id */
@@ -170,39 +252,57 @@
                 /* task_y */
                 eq(TASK_UPDATE.taskY),
                 /* session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UNSET_UNMINIMIZE_REASON),
                 /* visible_task_count */
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
-
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellDesktopModeTaskUpdate(
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED
+                ),
                 eq(TASK_UPDATE.instanceId),
                 eq(TASK_UPDATE.uid),
                 eq(TASK_UPDATE.taskHeight),
                 eq(TASK_UPDATE.taskWidth),
                 eq(TASK_UPDATE.taskX),
                 eq(TASK_UPDATE.taskY),
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UNSET_UNMINIMIZE_REASON),
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
-    fun logTaskInfoChanged_taskUpdate() = runBlocking {
-        desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID, TASK_UPDATE)
+    fun logTaskInfoChanged_noOngoingSession_doesNotLog() {
+        desktopModeEventLogger.logTaskInfoChanged(TASK_UPDATE)
+
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+    }
+
+    @Test
+    fun logTaskInfoChanged_taskUpdate() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskInfoChanged(TASK_UPDATE)
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                 /* task_event */
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED
+                ),
                 /* instance_id */
                 eq(TASK_UPDATE.instanceId),
                 /* uid */
@@ -216,40 +316,51 @@
                 /* task_y */
                 eq(TASK_UPDATE.taskY),
                 /* session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UNSET_UNMINIMIZE_REASON),
                 /* visible_task_count */
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
-
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellDesktopModeTaskUpdate(
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED
+                ),
                 eq(TASK_UPDATE.instanceId),
                 eq(TASK_UPDATE.uid),
                 eq(TASK_UPDATE.taskHeight),
                 eq(TASK_UPDATE.taskWidth),
                 eq(TASK_UPDATE.taskX),
                 eq(TASK_UPDATE.taskY),
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UNSET_UNMINIMIZE_REASON),
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
-    fun logTaskInfoChanged_logsTaskUpdateWithMinimizeReason() = runBlocking {
-        desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID,
-            createTaskUpdate(minimizeReason = MinimizeReason.TASK_LIMIT))
+    fun logTaskInfoChanged_logsTaskUpdateWithMinimizeReason() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskInfoChanged(
+            createTaskUpdate(minimizeReason = MinimizeReason.TASK_LIMIT)
+        )
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                 /* task_event */
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED
+                ),
                 /* instance_id */
                 eq(TASK_UPDATE.instanceId),
                 /* uid */
@@ -263,42 +374,53 @@
                 /* task_y */
                 eq(TASK_UPDATE.taskY),
                 /* session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 /* minimize_reason */
                 eq(MinimizeReason.TASK_LIMIT.reason),
                 /* unminimize_reason */
                 eq(UNSET_UNMINIMIZE_REASON),
                 /* visible_task_count */
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
-
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellDesktopModeTaskUpdate(
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED
+                ),
                 eq(TASK_UPDATE.instanceId),
                 eq(TASK_UPDATE.uid),
                 eq(TASK_UPDATE.taskHeight),
                 eq(TASK_UPDATE.taskWidth),
                 eq(TASK_UPDATE.taskX),
                 eq(TASK_UPDATE.taskY),
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(MinimizeReason.TASK_LIMIT.reason),
                 eq(UNSET_UNMINIMIZE_REASON),
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
-    fun logTaskInfoChanged_logsTaskUpdateWithUnminimizeReason() = runBlocking {
-        desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID,
-            createTaskUpdate(unminimizeReason = UnminimizeReason.TASKBAR_TAP))
+    fun logTaskInfoChanged_logsTaskUpdateWithUnminimizeReason() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskInfoChanged(
+            createTaskUpdate(unminimizeReason = UnminimizeReason.TASKBAR_TAP)
+        )
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                 /* task_event */
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED
+                ),
                 /* instance_id */
                 eq(TASK_UPDATE.instanceId),
                 /* uid */
@@ -312,39 +434,55 @@
                 /* task_y */
                 eq(TASK_UPDATE.taskY),
                 /* session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 /* minimize_reason */
                 eq(UNSET_MINIMIZE_REASON),
                 /* unminimize_reason */
                 eq(UnminimizeReason.TASKBAR_TAP.reason),
                 /* visible_task_count */
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
-
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
         verify {
             EventLogTags.writeWmShellDesktopModeTaskUpdate(
-                eq(FrameworkStatsLog
-                    .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                eq(
+                    FrameworkStatsLog
+                        .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED
+                ),
                 eq(TASK_UPDATE.instanceId),
                 eq(TASK_UPDATE.uid),
                 eq(TASK_UPDATE.taskHeight),
                 eq(TASK_UPDATE.taskWidth),
                 eq(TASK_UPDATE.taskX),
                 eq(TASK_UPDATE.taskY),
-                eq(SESSION_ID),
+                eq(sessionId),
                 eq(UNSET_MINIMIZE_REASON),
                 eq(UnminimizeReason.TASKBAR_TAP.reason),
-                eq(TASK_COUNT))
+                eq(TASK_COUNT)
+            )
         }
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
+    }
+
+    @Test
+    fun logTaskResizingStarted_noOngoingSession_doesNotLog() {
+        desktopModeEventLogger.logTaskResizingStarted(TASK_SIZE_UPDATE)
+
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_RESIZING_METRICS)
-    fun logTaskResizingStarted_logsTaskSizeUpdatedWithStartResizingStage() = runBlocking {
-        desktopModeEventLogger.logTaskResizingStarted(sessionId = SESSION_ID, createTaskSizeUpdate())
+    fun logTaskResizingStarted_logsTaskSizeUpdatedWithStartResizingStage() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskResizingStarted(TASK_SIZE_UPDATE)
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED),
                 /* resize_trigger */
                 eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZE_TRIGGER__UNKNOWN_RESIZE_TRIGGER),
                 /* resizing_stage */
@@ -352,7 +490,7 @@
                 /* input_method */
                 eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__INPUT_METHOD__UNKNOWN_INPUT_METHOD),
                 /* desktop_mode_session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 /* instance_id */
                 eq(TASK_SIZE_UPDATE.instanceId),
                 /* uid */
@@ -365,15 +503,27 @@
                 eq(TASK_SIZE_UPDATE.displayArea),
             )
         }
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+    }
+
+    @Test
+    fun logTaskResizingEnded_noOngoingSession_doesNotLog() {
+        desktopModeEventLogger.logTaskResizingEnded(TASK_SIZE_UPDATE)
+
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+        verifyZeroInteractions(staticMockMarker(EventLogTags::class.java))
     }
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_RESIZING_METRICS)
-    fun logTaskResizingEnded_logsTaskSizeUpdatedWithEndResizingStage() = runBlocking {
-        desktopModeEventLogger.logTaskResizingEnded(sessionId = SESSION_ID, createTaskSizeUpdate())
+    fun logTaskResizingEnded_logsTaskSizeUpdatedWithEndResizingStage() {
+        val sessionId = startDesktopModeSession()
+
+        desktopModeEventLogger.logTaskResizingEnded(TASK_SIZE_UPDATE)
 
         verify {
-            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED),
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED),
                 /* resize_trigger */
                 eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZE_TRIGGER__UNKNOWN_RESIZE_TRIGGER),
                 /* resizing_stage */
@@ -381,7 +531,7 @@
                 /* input_method */
                 eq(FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__INPUT_METHOD__UNKNOWN_INPUT_METHOD),
                 /* desktop_mode_session_id */
-                eq(SESSION_ID),
+                eq(sessionId),
                 /* instance_id */
                 eq(TASK_SIZE_UPDATE.instanceId),
                 /* uid */
@@ -394,6 +544,14 @@
                 eq(TASK_SIZE_UPDATE.displayArea),
             )
         }
+        verifyZeroInteractions(staticMockMarker(FrameworkStatsLog::class.java))
+    }
+
+    private fun startDesktopModeSession(): Int {
+        desktopModeEventLogger.logSessionEnter(EnterReason.KEYBOARD_SHORTCUT_ENTER)
+        clearInvocations(staticMockMarker(FrameworkStatsLog::class.java))
+        clearInvocations(staticMockMarker(EventLogTags::class.java))
+        return desktopModeEventLogger.currentSessionId.get()
     }
 
     @Test
@@ -428,7 +586,7 @@
     }
 
     private companion object {
-        private const val SESSION_ID = 1
+        private const val sessionId = 1
         private const val TASK_ID = 1
         private const val TASK_UID = 1
         private const val TASK_X = 0
@@ -453,23 +611,12 @@
             DISPLAY_AREA,
         )
 
-        private fun createTaskSizeUpdate(
-            resizeTrigger: ResizeTrigger = ResizeTrigger.UNKNOWN_RESIZE_TRIGGER,
-            inputMethod: InputMethod = InputMethod.UNKNOWN_INPUT_METHOD,
-        ) = TaskSizeUpdate(
-            resizeTrigger,
-            inputMethod,
-            TASK_ID,
-            TASK_UID,
-            TASK_HEIGHT,
-            TASK_WIDTH,
-            DISPLAY_AREA,
-        )
-
         private fun createTaskUpdate(
             minimizeReason: MinimizeReason? = null,
             unminimizeReason: UnminimizeReason? = null,
-        ) = TaskUpdate(TASK_ID, TASK_UID, TASK_HEIGHT, TASK_WIDTH, TASK_X, TASK_Y, minimizeReason,
-            unminimizeReason, TASK_COUNT)
+        ) = TaskUpdate(
+            TASK_ID, TASK_UID, TASK_HEIGHT, TASK_WIDTH, TASK_X, TASK_Y, minimizeReason,
+            unminimizeReason, TASK_COUNT
+        )
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index e7593b5..f25faa5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -59,8 +59,8 @@
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.TransitionInfoBuilder
 import com.android.wm.shell.transition.Transitions
-import junit.framework.Assert.assertNotNull
-import junit.framework.Assert.assertNull
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -142,8 +142,8 @@
 
     callOnTransitionReady(transitionInfo)
 
-    verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
-    verify(desktopModeEventLogger, never()).logTaskAdded(any(), any())
+    verify(desktopModeEventLogger, never()).logSessionEnter(any())
+    verify(desktopModeEventLogger, never()).logTaskAdded(any())
   }
 
   @Test
@@ -228,11 +228,10 @@
   @Test
   fun transitToFront_previousTransitionExitToOverview_logTaskAddedAndEnterReasonOverview() {
     // previous exit to overview transition
-    val previousSessionId = 1
     // add a freeform task
     val previousTaskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(previousTaskInfo)
-    transitionObserver.setLoggerSessionId(previousSessionId)
+    transitionObserver.isSessionActive = true
     val previousTransitionInfo =
         TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
             .addChange(createChange(TRANSIT_TO_BACK, previousTaskInfo))
@@ -241,7 +240,8 @@
     callOnTransitionReady(previousTransitionInfo)
 
     verifyTaskRemovedAndExitLogging(
-        previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+        ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE
+    )
 
     // Enter desktop mode from cancelled recents has no transition. Enter is detected on the
     // next transition involving freeform windows
@@ -259,11 +259,10 @@
   @Test
   fun transitChange_previousTransitionExitToOverview_logTaskAddedAndEnterReasonOverview() {
     // previous exit to overview transition
-    val previousSessionId = 1
     // add a freeform task
     val previousTaskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(previousTaskInfo)
-    transitionObserver.setLoggerSessionId(previousSessionId)
+    transitionObserver.isSessionActive = true
     val previousTransitionInfo =
         TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
             .addChange(createChange(TRANSIT_TO_BACK, previousTaskInfo))
@@ -272,7 +271,8 @@
     callOnTransitionReady(previousTransitionInfo)
 
     verifyTaskRemovedAndExitLogging(
-        previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+        ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE
+    )
 
     // Enter desktop mode from cancelled recents has no transition. Enter is detected on the
     // next transition involving freeform windows
@@ -290,11 +290,10 @@
   @Test
   fun transitOpen_previousTransitionExitToOverview_logTaskAddedAndEnterReasonOverview() {
     // previous exit to overview transition
-    val previousSessionId = 1
     // add a freeform task
     val previousTaskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(previousTaskInfo)
-    transitionObserver.setLoggerSessionId(previousSessionId)
+    transitionObserver.isSessionActive = true
     val previousTransitionInfo =
         TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
             .addChange(createChange(TRANSIT_TO_BACK, previousTaskInfo))
@@ -303,7 +302,8 @@
     callOnTransitionReady(previousTransitionInfo)
 
     verifyTaskRemovedAndExitLogging(
-        previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+        ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE
+    )
 
     // Enter desktop mode from cancelled recents has no transition. Enter is detected on the
     // next transition involving freeform windows
@@ -324,11 +324,10 @@
     // Tests for AppFromOverview precedence in compared to cancelled Overview
 
     // previous exit to overview transition
-    val previousSessionId = 1
     // add a freeform task
     val previousTaskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(previousTaskInfo)
-    transitionObserver.setLoggerSessionId(previousSessionId)
+    transitionObserver.isSessionActive = true
     val previousTransitionInfo =
         TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
             .addChange(createChange(TRANSIT_TO_BACK, previousTaskInfo))
@@ -337,7 +336,8 @@
     callOnTransitionReady(previousTransitionInfo)
 
     verifyTaskRemovedAndExitLogging(
-        previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+        ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE
+    )
 
     // TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
     val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FREEFORM))
@@ -379,11 +379,10 @@
   fun transitBack_previousExitReasonScreenOff_logTaskAddedAndEnterReasonScreenOn() {
     val freeformTask = createTaskInfo(WINDOWING_MODE_FREEFORM)
     // Previous Exit reason recorded as Screen Off
-    val sessionId = 1
     transitionObserver.addTaskInfosToCachedMap(freeformTask)
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
     callOnTransitionReady(TransitionInfoBuilder(TRANSIT_SLEEP).build())
-    verifyTaskRemovedAndExitLogging(sessionId, ExitReason.SCREEN_OFF, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.SCREEN_OFF, DEFAULT_TASK_UPDATE)
     // Enter desktop through back transition, this happens when user enters after dismissing
     // keyguard
     val change = createChange(TRANSIT_TO_FRONT, freeformTask)
@@ -399,11 +398,10 @@
   fun transitEndDragToDesktop_previousExitReasonScreenOff_logTaskAddedAndEnterReasonAppDrag() {
     val freeformTask = createTaskInfo(WINDOWING_MODE_FREEFORM)
     // Previous Exit reason recorded as Screen Off
-    val sessionId = 1
     transitionObserver.addTaskInfosToCachedMap(freeformTask)
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
     callOnTransitionReady(TransitionInfoBuilder(TRANSIT_SLEEP).build())
-    verifyTaskRemovedAndExitLogging(sessionId, ExitReason.SCREEN_OFF, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.SCREEN_OFF, DEFAULT_TASK_UPDATE)
 
     // Enter desktop through app handle drag. This represents cases where instead of moving to
     // desktop right after turning the screen on, we move to fullscreen then move another task
@@ -419,24 +417,22 @@
   }
 
   @Test
-  fun transitSleep_logTaskRemovedAndExitReasonScreenOff_sessionIdNull() {
-    val sessionId = 1
+  fun transitSleep_logTaskRemovedAndExitReasonScreenOff() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     val transitionInfo = TransitionInfoBuilder(TRANSIT_SLEEP).build()
     callOnTransitionReady(transitionInfo)
 
-    verifyTaskRemovedAndExitLogging(sessionId, ExitReason.SCREEN_OFF, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.SCREEN_OFF, DEFAULT_TASK_UPDATE)
   }
 
   @Test
-  fun transitExitDesktopTaskDrag_logTaskRemovedAndExitReasonDragToExit_sessionIdNull() {
-    val sessionId = 1
+  fun transitExitDesktopTaskDrag_logTaskRemovedAndExitReasonDragToExit() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // window mode changing from FREEFORM to FULLSCREEN
     val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FULLSCREEN))
@@ -444,15 +440,14 @@
         TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG).addChange(change).build()
     callOnTransitionReady(transitionInfo)
 
-    verifyTaskRemovedAndExitLogging(sessionId, ExitReason.DRAG_TO_EXIT, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.DRAG_TO_EXIT, DEFAULT_TASK_UPDATE)
   }
 
   @Test
-  fun transitExitDesktopAppHandleButton_logTaskRemovedAndExitReasonButton_sessionIdNull() {
-    val sessionId = 1
+  fun transitExitDesktopAppHandleButton_logTaskRemovedAndExitReasonButton() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // window mode changing from FREEFORM to FULLSCREEN
     val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FULLSCREEN))
@@ -462,16 +457,14 @@
             .build()
     callOnTransitionReady(transitionInfo)
 
-    verifyTaskRemovedAndExitLogging(
-        sessionId, ExitReason.APP_HANDLE_MENU_BUTTON_EXIT, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.APP_HANDLE_MENU_BUTTON_EXIT, DEFAULT_TASK_UPDATE)
   }
 
   @Test
-  fun transitExitDesktopUsingKeyboard_logTaskRemovedAndExitReasonKeyboard_sessionIdNull() {
-    val sessionId = 1
+  fun transitExitDesktopUsingKeyboard_logTaskRemovedAndExitReasonKeyboard() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // window mode changing from FREEFORM to FULLSCREEN
     val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FULLSCREEN))
@@ -479,16 +472,14 @@
         TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT).addChange(change).build()
     callOnTransitionReady(transitionInfo)
 
-    verifyTaskRemovedAndExitLogging(
-        sessionId, ExitReason.KEYBOARD_SHORTCUT_EXIT, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.KEYBOARD_SHORTCUT_EXIT, DEFAULT_TASK_UPDATE)
   }
 
   @Test
-  fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown_sessionIdNull() {
-    val sessionId = 1
+  fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // window mode changing from FREEFORM to FULLSCREEN
     val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FULLSCREEN))
@@ -496,15 +487,14 @@
         TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN).addChange(change).build()
     callOnTransitionReady(transitionInfo)
 
-    verifyTaskRemovedAndExitLogging(sessionId, ExitReason.UNKNOWN_EXIT, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.UNKNOWN_EXIT, DEFAULT_TASK_UPDATE)
   }
 
   @Test
-  fun transitToFrontWithFlagRecents_logTaskRemovedAndExitReasonOverview_sessionIdNull() {
-    val sessionId = 1
+  fun transitToFrontWithFlagRecents_logTaskRemovedAndExitReasonOverview() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // recents transition
     val change = createChange(TRANSIT_TO_BACK, createTaskInfo(WINDOWING_MODE_FREEFORM))
@@ -513,31 +503,30 @@
     callOnTransitionReady(transitionInfo)
 
     verifyTaskRemovedAndExitLogging(
-        sessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+        ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE
+    )
   }
 
   @Test
-  fun transitClose_logTaskRemovedAndExitReasonTaskFinished_sessionIdNull() {
-    val sessionId = 1
+  fun transitClose_logTaskRemovedAndExitReasonTaskFinished() {
     // add a freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // task closing
     val change = createChange(TRANSIT_CLOSE, createTaskInfo(WINDOWING_MODE_FULLSCREEN))
     val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE).addChange(change).build()
     callOnTransitionReady(transitionInfo)
 
-    verifyTaskRemovedAndExitLogging(sessionId, ExitReason.TASK_FINISHED, DEFAULT_TASK_UPDATE)
+    verifyTaskRemovedAndExitLogging(ExitReason.TASK_FINISHED, DEFAULT_TASK_UPDATE)
   }
 
   @Test
   fun sessionExitByRecents_cancelledAnimation_sessionRestored() {
-    val sessionId = 1
     // add a freeform task to an existing session
     val taskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(taskInfo)
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // recents transition sent freeform window to back
     val change = createChange(TRANSIT_TO_BACK, taskInfo)
@@ -546,7 +535,8 @@
     callOnTransitionReady(transitionInfo1)
 
     verifyTaskRemovedAndExitLogging(
-        sessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+        ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE
+    )
 
     val transitionInfo2 = TransitionInfoBuilder(TRANSIT_NONE).build()
     callOnTransitionReady(transitionInfo2)
@@ -557,10 +547,9 @@
 
   @Test
   fun sessionAlreadyStarted_newFreeformTaskAdded_logsTaskAdded() {
-    val sessionId = 1
     // add an existing freeform task
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // new freeform task added
     val change = createChange(TRANSIT_OPEN, createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2))
@@ -568,18 +557,16 @@
     callOnTransitionReady(transitionInfo)
 
     verify(desktopModeEventLogger, times(1))
-        .logTaskAdded(eq(sessionId),
-            eq(DEFAULT_TASK_UPDATE.copy(instanceId = 2, visibleTaskCount = 2)))
-    verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
+        .logTaskAdded(eq(DEFAULT_TASK_UPDATE.copy(instanceId = 2, visibleTaskCount = 2)))
+    verify(desktopModeEventLogger, never()).logSessionEnter(any())
   }
 
   @Test
   fun sessionAlreadyStarted_taskPositionChanged_logsTaskUpdate() {
-    val sessionId = 1
     // add an existing freeform task
     val taskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(taskInfo)
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // task position changed
     val newTaskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM, taskX = DEFAULT_TASK_X + 100)
@@ -591,18 +578,17 @@
 
     verify(desktopModeEventLogger, times(1))
         .logTaskInfoChanged(
-            eq(sessionId),
-            eq(DEFAULT_TASK_UPDATE.copy(taskX = DEFAULT_TASK_X + 100, visibleTaskCount = 1)))
+            eq(DEFAULT_TASK_UPDATE.copy(taskX = DEFAULT_TASK_X + 100, visibleTaskCount = 1))
+        )
     verifyZeroInteractions(desktopModeEventLogger)
   }
 
   @Test
   fun sessionAlreadyStarted_taskResized_logsTaskUpdate() {
-    val sessionId = 1
     // add an existing freeform task
     val taskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
     transitionObserver.addTaskInfosToCachedMap(taskInfo)
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // task resized
     val newTaskInfo =
@@ -618,23 +604,22 @@
 
     verify(desktopModeEventLogger, times(1))
         .logTaskInfoChanged(
-            eq(sessionId),
             eq(
                 DEFAULT_TASK_UPDATE.copy(
                     taskWidth = DEFAULT_TASK_WIDTH + 100, taskHeight = DEFAULT_TASK_HEIGHT - 100,
-                    visibleTaskCount = 1)))
+                    visibleTaskCount = 1))
+        )
     verifyZeroInteractions(desktopModeEventLogger)
   }
 
   @Test
   fun sessionAlreadyStarted_multipleTasksUpdated_logsTaskUpdateForCorrectTask() {
-    val sessionId = 1
     // add 2 existing freeform task
     val taskInfo1 = createTaskInfo(WINDOWING_MODE_FREEFORM)
     val taskInfo2 = createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2)
     transitionObserver.addTaskInfosToCachedMap(taskInfo1)
     transitionObserver.addTaskInfosToCachedMap(taskInfo2)
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // task 1 position update
     val newTaskInfo1 = createTaskInfo(WINDOWING_MODE_FREEFORM, taskX = DEFAULT_TASK_X + 100)
@@ -646,8 +631,9 @@
 
     verify(desktopModeEventLogger, times(1))
         .logTaskInfoChanged(
-            eq(sessionId), eq(DEFAULT_TASK_UPDATE.copy(
-                taskX = DEFAULT_TASK_X + 100, visibleTaskCount = 2)))
+            eq(DEFAULT_TASK_UPDATE.copy(
+                taskX = DEFAULT_TASK_X + 100, visibleTaskCount = 2))
+        )
     verifyZeroInteractions(desktopModeEventLogger)
 
     // task 2 resize
@@ -666,7 +652,6 @@
 
     verify(desktopModeEventLogger, times(1))
         .logTaskInfoChanged(
-            eq(sessionId),
             eq(
                 DEFAULT_TASK_UPDATE.copy(
                     instanceId = 2,
@@ -679,11 +664,10 @@
 
   @Test
   fun sessionAlreadyStarted_freeformTaskRemoved_logsTaskRemoved() {
-    val sessionId = 1
     // add two existing freeform tasks
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM))
     transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2))
-    transitionObserver.setLoggerSessionId(sessionId)
+    transitionObserver.isSessionActive = true
 
     // new freeform task closed
     val change = createChange(TRANSIT_CLOSE, createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2))
@@ -691,9 +675,11 @@
     callOnTransitionReady(transitionInfo)
 
     verify(desktopModeEventLogger, times(1))
-        .logTaskRemoved(eq(sessionId), eq(DEFAULT_TASK_UPDATE.copy(
-            instanceId = 2, visibleTaskCount = 1)))
-    verify(desktopModeEventLogger, never()).logSessionExit(any(), any())
+        .logTaskRemoved(
+            eq(DEFAULT_TASK_UPDATE.copy(
+                instanceId = 2, visibleTaskCount = 1))
+        )
+    verify(desktopModeEventLogger, never()).logSessionExit(any())
   }
 
   /** Simulate calling the onTransitionReady() method */
@@ -706,10 +692,9 @@
   }
 
   private fun verifyTaskAddedAndEnterLogging(enterReason: EnterReason, taskUpdate: TaskUpdate) {
-    val sessionId = transitionObserver.getLoggerSessionId()
-    assertNotNull(sessionId)
-    verify(desktopModeEventLogger, times(1)).logSessionEnter(eq(sessionId!!), eq(enterReason))
-    verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), eq(taskUpdate))
+    assertTrue(transitionObserver.isSessionActive)
+    verify(desktopModeEventLogger, times(1)).logSessionEnter(eq(enterReason))
+    verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(taskUpdate))
     ExtendedMockito.verify {
         Trace.setCounter(
             eq(Trace.TRACE_TAG_WINDOW_MANAGER),
@@ -725,14 +710,13 @@
   }
 
   private fun verifyTaskRemovedAndExitLogging(
-      sessionId: Int,
       exitReason: ExitReason,
       taskUpdate: TaskUpdate
   ) {
-    verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), eq(taskUpdate))
-    verify(desktopModeEventLogger, times(1)).logSessionExit(eq(sessionId), eq(exitReason))
+    assertFalse(transitionObserver.isSessionActive)
+    verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(taskUpdate))
+    verify(desktopModeEventLogger, times(1)).logSessionExit(eq(exitReason))
     verifyZeroInteractions(desktopModeEventLogger)
-    assertNull(transitionObserver.getLoggerSessionId())
   }
 
   private companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 230f7e6..0bd3e08 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -1,5 +1,6 @@
 package com.android.wm.shell.desktopmode
 
+import android.animation.AnimatorTestRule
 import android.app.ActivityManager.RunningTaskInfo
 import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
 import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
@@ -24,6 +25,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
 import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
 import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
 import com.android.wm.shell.splitscreen.SplitScreenController
@@ -38,6 +40,7 @@
 import junit.framework.Assert.assertTrue
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.any
@@ -58,6 +61,9 @@
 @RunWithLooper
 @RunWith(AndroidTestingRunner::class)
 class DragToDesktopTransitionHandlerTest : ShellTestCase() {
+    @JvmField
+    @Rule
+    val mAnimatorTestRule = AnimatorTestRule(this)
 
     @Mock private lateinit var transitions: Transitions
     @Mock private lateinit var taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@@ -267,16 +273,36 @@
     }
 
     @Test
-    fun cancelDragToDesktop_startWasReady_cancel() {
-        startDrag(defaultHandler)
+    fun cancelDragToDesktop_startWasReady_cancel_merged() {
+        val startToken = startDrag(defaultHandler)
 
         // Then user cancelled after it had already started.
-        defaultHandler.cancelDragToDesktopTransition(
-            DragToDesktopTransitionHandler.CancelState.STANDARD_CANCEL
-        )
+        val cancelToken = cancelDragToDesktopTransition(
+            defaultHandler, DragToDesktopTransitionHandler.CancelState.STANDARD_CANCEL)
+        defaultHandler.mergeAnimation(
+            cancelToken,
+            TransitionInfo(TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP, 0),
+            mock<SurfaceControl.Transaction>(),
+            startToken,
+            mock<Transitions.TransitionFinishCallback>())
 
         // Cancel animation should run since it had already started.
         verify(dragAnimator).cancelAnimator()
+        assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress)
+    }
+
+    @Test
+    fun cancelDragToDesktop_startWasReady_cancel_aborted() {
+        val startToken = startDrag(defaultHandler)
+
+        // Then user cancelled after it had already started.
+        val cancelToken = cancelDragToDesktopTransition(
+            defaultHandler, DragToDesktopTransitionHandler.CancelState.STANDARD_CANCEL)
+        defaultHandler.onTransitionConsumed(cancelToken, aborted = true, null)
+
+        // Cancel animation should run since it had already started.
+        verify(dragAnimator).cancelAnimator()
+        assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress)
     }
 
     @Test
@@ -585,6 +611,23 @@
         return token
     }
 
+    private fun cancelDragToDesktopTransition(
+        handler: DragToDesktopTransitionHandler,
+        cancelState: DragToDesktopTransitionHandler.CancelState): IBinder {
+        val token = mock<IBinder>()
+        whenever(
+                transitions.startTransition(
+                    eq(TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP),
+                    any(),
+                    eq(handler)
+                )
+            )
+            .thenReturn(token)
+        handler.cancelDragToDesktopTransition(cancelState)
+        mAnimatorTestRule.advanceTimeBy(DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS)
+        return token
+    }
+
     private fun performEarlyCancel(
         handler: DragToDesktopTransitionHandler,
         cancelState: DragToDesktopTransitionHandler.CancelState
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index b7b7d0d..189684d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -23,10 +23,9 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.app.ActivityManager;
@@ -64,8 +63,6 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public final class StageTaskListenerTests extends ShellTestCase {
-    private static final boolean ENABLE_SHELL_TRANSITIONS =
-            SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
 
     @Mock
     private ShellTaskOrganizer mTaskOrganizer;
@@ -117,20 +114,20 @@
     public void testRootTaskAppeared() {
         assertThat(mStageTaskListener.mRootTaskInfo.taskId).isEqualTo(mRootTask.taskId);
         verify(mCallbacks).onRootTaskAppeared();
-        verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(false));
+        verify(mCallbacks, never()).onStageHasChildrenChanged(mStageTaskListener);
+        verify(mCallbacks, never()).onStageVisibilityChanged(mStageTaskListener);
     }
 
     @Test
-    public void testChildTaskAppeared() {
-        // With shell transitions, the transition manages status changes, so skip this test.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
-        final ActivityManager.RunningTaskInfo childTask =
-                new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build();
+    public void testRootTaskVisible() {
+        mStageTaskListener.onTaskVanished(mRootTask);
+        mRootTask = new TestRunningTaskInfoBuilder().setVisible(true).build();
+        mRootTask.parentTaskId = INVALID_TASK_ID;
+        mSurfaceControl = new SurfaceControl.Builder().setName("test").build();
+        mStageTaskListener.onTaskAppeared(mRootTask, mSurfaceControl);
 
-        mStageTaskListener.onTaskAppeared(childTask, mSurfaceControl);
+        verify(mCallbacks).onStageVisibilityChanged(mStageTaskListener);
 
-        assertThat(mStageTaskListener.mChildrenTaskInfo.contains(childTask.taskId)).isTrue();
-        verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true));
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -140,29 +137,13 @@
     }
 
     @Test
-    public void testTaskVanished() {
-        // With shell transitions, the transition manages status changes, so skip this test.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
-        final ActivityManager.RunningTaskInfo childTask =
-                new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build();
-        mStageTaskListener.mRootTaskInfo = mRootTask;
-        mStageTaskListener.mChildrenTaskInfo.put(childTask.taskId, childTask);
-
-        mStageTaskListener.onTaskVanished(childTask);
-        verify(mCallbacks, times(2)).onStatusChanged(eq(mRootTask.isVisible), eq(false));
-
-        mStageTaskListener.onTaskVanished(mRootTask);
-        verify(mCallbacks).onRootTaskVanished();
-    }
-
-    @Test
     public void testTaskInfoChanged_notSupportsMultiWindow() {
         final ActivityManager.RunningTaskInfo childTask =
                 new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build();
         childTask.supportsMultiWindow = false;
 
         mStageTaskListener.onTaskInfoChanged(childTask);
-        verify(mCallbacks).onNoLongerSupportMultiWindow(childTask);
+        verify(mCallbacks).onNoLongerSupportMultiWindow(mStageTaskListener, childTask);
     }
 
     @Test
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cdb517b3..536afd4 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -51,6 +51,7 @@
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.Overridable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -1918,12 +1919,18 @@
     @Deprecated public void setSpeakerphoneOn(boolean on) {
         final IAudioService service = getService();
         try {
-            service.setSpeakerphoneOn(mICallBack, on);
+            service.setSpeakerphoneOn(mICallBack, on, getAttributionSource());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    private AttributionSource getAttributionSource() {
+        Context context = getContext();
+        return (context != null)
+                     ? context.getAttributionSource() : AttributionSource.myAttributionSource();
+    }
+
     /**
      * Checks whether the speakerphone is on or off.
      *
@@ -3089,7 +3096,8 @@
         final IAudioService service = getService();
         try {
             service.startBluetoothSco(mICallBack,
-                    getContext().getApplicationInfo().targetSdkVersion);
+                    getContext().getApplicationInfo().targetSdkVersion,
+                    getAttributionSource());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3114,7 +3122,7 @@
     public void startBluetoothScoVirtualCall() {
         final IAudioService service = getService();
         try {
-            service.startBluetoothScoVirtualCall(mICallBack);
+            service.startBluetoothScoVirtualCall(mICallBack, getAttributionSource());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3134,7 +3142,7 @@
     @Deprecated public void stopBluetoothSco() {
         final IAudioService service = getService();
         try {
-            service.stopBluetoothSco(mICallBack);
+            service.stopBluetoothSco(mICallBack,  getAttributionSource());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -9023,7 +9031,8 @@
                 Log.w(TAG, "setCommunicationDevice: device not found: " + device);
                 return false;
             }
-            return getService().setCommunicationDevice(mICallBack, device.getId());
+            return getService().setCommunicationDevice(mICallBack, device.getId(),
+                    getAttributionSource());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -9035,7 +9044,7 @@
      */
     public void clearCommunicationDevice() {
         try {
-            getService().setCommunicationDevice(mICallBack, 0);
+            getService().setCommunicationDevice(mICallBack, 0, getAttributionSource());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 4d6ddfd..3cd5f52 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -18,7 +18,9 @@
 
 import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_ALL;
 import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_NONE;
+import static android.media.audio.Flags.FLAG_MUTED_BY_PORT_VOLUME_API;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -291,12 +293,24 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public static final int MUTED_BY_VOLUME_SHAPER = (1 << 5);
+    /**
+     * @hide
+     * Flag used when muted by the track's port volume.
+     *
+     * <p>Note: this will replace the stream volume mute when using the AudioFlinger port volume
+     * APIs
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_MUTED_BY_PORT_VOLUME_API)
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public static final int MUTED_BY_PORT_VOLUME = (1 << 6);
 
     /** @hide */
     @IntDef(
             flag = true,
             value = {MUTED_BY_MASTER, MUTED_BY_STREAM_VOLUME, MUTED_BY_STREAM_MUTED,
-                    MUTED_BY_APP_OPS, MUTED_BY_CLIENT_VOLUME, MUTED_BY_VOLUME_SHAPER})
+                    MUTED_BY_APP_OPS, MUTED_BY_CLIENT_VOLUME, MUTED_BY_VOLUME_SHAPER,
+                    MUTED_BY_PORT_VOLUME})
     @Retention(RetentionPolicy.SOURCE)
     public @interface PlayerMuteEvent {
     }
@@ -858,6 +872,9 @@
                 if ((mMutedState & MUTED_BY_VOLUME_SHAPER) != 0) {
                     apcToString.append("volumeShaper ");
                 }
+                if ((mMutedState & MUTED_BY_PORT_VOLUME) != 0) {
+                    apcToString.append("portVolume ");
+                }
             }
             apcToString.append(" ").append(mFormatInfo);
         }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index a8b863b..bf09cb0 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1698,12 +1698,12 @@
     }
 
     /** @hide Wrapper for native methods called from AudioService */
-    public static int setStreamVolumeIndexAS(int stream, int index, int device) {
+    public static int setStreamVolumeIndexAS(int stream, int index, boolean muted, int device) {
         if (DEBUG_VOLUME) {
             Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]
-                    + " dev=" + Integer.toHexString(device) + " idx=" + index);
+                    + " dev=" + Integer.toHexString(device) + " idx=" + index + " muted=" + muted);
         }
-        return setStreamVolumeIndex(stream, index, device);
+        return setStreamVolumeIndex(stream, index, muted, device);
     }
 
     // usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
@@ -1774,7 +1774,8 @@
     @UnsupportedAppUsage
     public static native int initStreamVolume(int stream, int indexMin, int indexMax);
     @UnsupportedAppUsage
-    private static native int setStreamVolumeIndex(int stream, int index, int device);
+    private static native int setStreamVolumeIndex(int stream, int index, boolean muted,
+            int device);
     /** @hide */
     public static native int getStreamVolumeIndex(int stream, int device);
     /**
@@ -1787,7 +1788,7 @@
      * @return command completion status.
      */
     public static native int setVolumeIndexForAttributes(@NonNull AudioAttributes attributes,
-                                                         int index, int device);
+                                                         int index, boolean muted, int device);
    /**
     * @hide
     * get the volume index for the given {@link AudioAttributes}.
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 8394daf..02ca307 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -234,7 +234,7 @@
 
     int getEncodedSurroundMode(int targetSdkVersion);
 
-    void setSpeakerphoneOn(IBinder cb, boolean on);
+    void setSpeakerphoneOn(IBinder cb, boolean on, in AttributionSource attributionSource);
 
     boolean isSpeakerphoneOn();
 
@@ -263,9 +263,10 @@
 
     int getCurrentAudioFocus();
 
-    void startBluetoothSco(IBinder cb, int targetSdkVersion);
-    void startBluetoothScoVirtualCall(IBinder cb);
-    void stopBluetoothSco(IBinder cb);
+    void startBluetoothSco(IBinder cb, int targetSdkVersion,
+            in AttributionSource attributionSource);
+    void startBluetoothScoVirtualCall(IBinder cb, in AttributionSource attributionSource);
+    void stopBluetoothSco(IBinder cb, in AttributionSource attributionSource);
 
     void forceVolumeControlStream(int streamType, IBinder cb);
 
@@ -542,7 +543,7 @@
 
     int[] getAvailableCommunicationDeviceIds();
 
-    boolean setCommunicationDevice(IBinder cb, int portId);
+    boolean setCommunicationDevice(IBinder cb, int portId, in AttributionSource attributionSource);
 
     int getCommunicationDevice();
 
diff --git a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
index b286182..601e001 100644
--- a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
+++ b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
@@ -57,7 +57,7 @@
  * 1. User sets invisible for button. ex: ActionButtonPreference.setButton1Visible(false)
  * 2. User doesn't set any title or icon for button.
  */
-public class ActionButtonsPreference extends Preference {
+public class ActionButtonsPreference extends Preference implements GroupSectionDividerMixin {
 
     private static final String TAG = "ActionButtonPreference";
     private static final boolean mIsAtLeastS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
index 6cd777e..10769ec 100644
--- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -43,7 +43,7 @@
  * Banner message is a banner displaying important information (permission request, page error etc),
  * and provide actions for user to address. It requires a user action to be dismissed.
  */
-public class BannerMessagePreference extends Preference {
+public class BannerMessagePreference extends Preference implements GroupSectionDividerMixin {
 
     public enum AttentionLevel {
         HIGH(0, R.color.banner_background_attention_high, R.color.banner_accent_attention_high),
diff --git a/packages/SettingsLib/CardPreference/src/com/android/settingslib/widget/CardPreference.kt b/packages/SettingsLib/CardPreference/src/com/android/settingslib/widget/CardPreference.kt
index eb14746..84ff1bb 100644
--- a/packages/SettingsLib/CardPreference/src/com/android/settingslib/widget/CardPreference.kt
+++ b/packages/SettingsLib/CardPreference/src/com/android/settingslib/widget/CardPreference.kt
@@ -30,7 +30,7 @@
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0,
     defStyleRes: Int = 0
-) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
 
     init {
         layoutResource = R.layout.settingslib_expressive_preference_card
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
index 8c5d877..8fb16d8 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -78,6 +78,10 @@
         for (activityClass in request.activityClasses) {
             add(activityClass)
         }
+        // Temporarily add all screens
+        for (key in PreferenceScreenRegistry.preferenceScreens.keys) {
+            addPreferenceScreenFromRegistry(key, Activity::class.java)
+        }
     }
 
     fun build() = builder.build()
diff --git a/packages/SettingsLib/IllustrationPreference/Android.bp b/packages/SettingsLib/IllustrationPreference/Android.bp
index cd8f584..12890fe 100644
--- a/packages/SettingsLib/IllustrationPreference/Android.bp
+++ b/packages/SettingsLib/IllustrationPreference/Android.bp
@@ -21,6 +21,7 @@
         "SettingsLibColor",
         "androidx.preference_preference",
         "lottie",
+        "SettingsLibSettingsTheme",
         "settingslib_illustrationpreference_flags_lib",
     ],
 
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index a0599bb..adc4f316 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -55,7 +55,7 @@
 /**
  * IllustrationPreference is a preference that can play lottie format animation
  */
-public class IllustrationPreference extends Preference {
+public class IllustrationPreference extends Preference implements GroupSectionDividerMixin {
 
     private static final String TAG = "IllustrationPreference";
 
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index e3f8fbb..2e3ee32 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -20,8 +20,6 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingTop="@dimen/settingslib_switchbar_margin"
     android:paddingBottom="@dimen/settingslib_switchbar_margin"
     android:orientation="vertical">
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
index 255b2c9..3e0e184 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
@@ -20,8 +20,6 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingTop="@dimen/settingslib_switchbar_margin"
     android:paddingBottom="@dimen/settingslib_switchbar_margin"
     android:orientation="vertical">
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v35/settingslib_expressive_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v35/settingslib_expressive_main_switch_bar.xml
index 4425ef0..f75d9b2 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v35/settingslib_expressive_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v35/settingslib_expressive_main_switch_bar.xml
@@ -20,8 +20,6 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:paddingVertical="@dimen/settingslib_expressive_space_small1"
     android:orientation="vertical">
 
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index bf34db9..7c0eaea 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -18,11 +18,7 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+    android:layout_width="match_parent">
 
     <TextView
         android:id="@+id/switch_text"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
index bef6e35..fa908a4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
@@ -18,6 +18,10 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
+    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:importantForAccessibility="no">
 
     <com.android.settingslib.widget.MainSwitchBar
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index d895c87..3394874 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -36,7 +36,8 @@
  * This component is used as the main switch of the page
  * to enable or disable the prefereces on the page.
  */
-public class MainSwitchPreference extends TwoStatePreference implements OnCheckedChangeListener {
+public class MainSwitchPreference extends TwoStatePreference
+        implements OnCheckedChangeListener, GroupSectionDividerMixin {
 
     private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>();
 
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt
index f39f3a0..33f2dbf 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt
@@ -31,6 +31,7 @@
  * information:
  * - [PreferenceTitleProvider]: provide dynamic title content
  * - [PreferenceSummaryProvider]: provide dynamic summary content (e.g. based on preference value)
+ * - [PreferenceIconProvider]: provide dynamic icon content (e.g. based on flag)
  * - [PreferenceAvailabilityProvider]: provide preference availability (e.g. based on flag)
  * - [PreferenceLifecycleProvider]: provide the lifecycle callbacks and notify state change
  *
@@ -160,6 +161,19 @@
             this is PreferenceSummaryProvider -> getSummary(context)
             else -> null
         }
+
+    /**
+     * Returns the preference icon.
+     *
+     * Implement [PreferenceIconProvider] interface if icon content is provided dynamically
+     * (e.g. icon is provided based on flag value).
+     */
+    fun getPreferenceIcon(context: Context): Int =
+        when {
+            icon != 0 -> icon
+            this is PreferenceIconProvider -> getIcon(context)
+            else -> 0
+        }
 }
 
 /** Metadata of preference group. */
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt
index 48798da..6646d6c3 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt
@@ -34,7 +34,7 @@
         ImmutableMap.of()
     }
 
-    private val preferenceScreens: PreferenceScreenMap
+    val preferenceScreens: PreferenceScreenMap
         get() = preferenceScreensSupplier.get()
 
     private var readWritePermitProvider: ReadWritePermitProvider? = null
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
index a3aa85d..98cba1c 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
@@ -41,6 +41,17 @@
 }
 
 /**
+ * Interface to provide dynamic preference icon.
+ *
+ * Implement this interface implies that the preference icon should not be cached for indexing.
+ */
+interface PreferenceIconProvider {
+
+    /** Provides preference icon. */
+    fun getIcon(context: Context): Int
+}
+
+/**
  * Interface to provide the state of preference availability.
  *
  * UI framework normally does not show the preference widget if it is unavailable.
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
index 5e69895..ef3d372 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
@@ -62,12 +62,13 @@
     fun bind(preference: Preference, metadata: PreferenceMetadata) {
         metadata.apply {
             preference.key = key
-            if (icon != 0) {
-                preference.setIcon(icon)
+            val context = preference.context
+            val preferenceIcon = metadata.getPreferenceIcon(context)
+            if (preferenceIcon != 0) {
+                preference.setIcon(preferenceIcon)
             } else {
                 preference.icon = null
             }
-            val context = preference.context
             val isPreferenceScreen = preference is PreferenceScreen
             preference.peekExtras()?.clear()
             extras(context)?.let { preference.extras.putAll(it) }
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
index debaf3e..d501f4f 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
@@ -41,6 +41,9 @@
         createPreferenceScreen(PreferenceScreenFactory(this))
 
     override fun createPreferenceScreen(factory: PreferenceScreenFactory): PreferenceScreen? {
+        preferenceScreenBindingHelper?.close()
+        preferenceScreenBindingHelper = null
+
         val context = factory.context
         fun createPreferenceScreenFromResource() =
             factory.inflate(getPreferenceScreenResId(context))?.also {
@@ -86,9 +89,13 @@
 
     override fun onDestroy() {
         preferenceScreenBindingHelper?.close()
+        preferenceScreenBindingHelper = null
         super.onDestroy()
     }
 
+    protected fun getPreferenceKeysInHierarchy(): Set<String> =
+        preferenceScreenBindingHelper?.getPreferences()?.map { it.key }?.toSet() ?: setOf()
+
     companion object {
         private const val TAG = "PreferenceFragment"
     }
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
index 3610894..95b921b 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
@@ -45,7 +45,7 @@
     context: Context,
     private val preferenceBindingFactory: PreferenceBindingFactory,
     private val preferenceScreen: PreferenceScreen,
-    preferenceHierarchy: PreferenceHierarchy,
+    private val preferenceHierarchy: PreferenceHierarchy,
 ) : KeyedDataObservable<String>(), AutoCloseable {
 
     private val handler = Handler(Looper.getMainLooper())
@@ -133,6 +133,8 @@
         }
     }
 
+    fun getPreferences() = preferenceHierarchy.getAllPreferences()
+
     override fun close() {
         removeObserver(preferenceObserver)
         val context = preferenceScreen.context
diff --git a/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/CatalystScreenTestCase.kt b/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/CatalystScreenTestCase.kt
index 4d5f85f..1412c84 100644
--- a/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/CatalystScreenTestCase.kt
+++ b/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/CatalystScreenTestCase.kt
@@ -27,6 +27,7 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.atomic.AtomicBoolean
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,15 +50,15 @@
      * catalyst screen (flag is enabled).
      */
     @Test
-    fun migration() {
+    open fun migration() {
         enableCatalystScreen()
         assertThat(preferenceScreenCreator.isFlagEnabled(context)).isTrue()
-        val catalystScreen = stringifyPreferenceScreen()
-        Log.i("Catalyst", catalystScreen)
+        val catalystScreen = dumpPreferenceScreen()
+        Log.i(TAG, catalystScreen)
 
         disableCatalystScreen()
         assertThat(preferenceScreenCreator.isFlagEnabled(context)).isFalse()
-        val legacyScreen = stringifyPreferenceScreen()
+        val legacyScreen = dumpPreferenceScreen()
 
         assertThat(catalystScreen).isEqualTo(legacyScreen)
     }
@@ -82,12 +83,27 @@
         setFlagsRule.disableFlags(flagName)
     }
 
-    private fun stringifyPreferenceScreen(): String {
+    private fun dumpPreferenceScreen(): String {
+        // Dump threads for troubleshooting when the test thread is stuck.
+        // Latest junit Timeout rule supports similar feature but it is not yet available on AOSP.
+        val taskFinished = AtomicBoolean()
+        Thread {
+                Thread.sleep(20000)
+                if (!taskFinished.get()) dumpThreads()
+            }
+            .apply {
+                isDaemon = true
+                start()
+            }
+
         @Suppress("UNCHECKED_CAST")
         val clazz = preferenceScreenCreator.fragmentClass() as Class<PreferenceFragmentCompat>
         val builder = StringBuilder()
         FragmentScenario.launch(clazz).use {
-            it.onFragment { fragment -> fragment.preferenceScreen.toString(builder) }
+            it.onFragment { fragment ->
+                taskFinished.set(true)
+                fragment.preferenceScreen.toString(builder)
+            }
         }
         return builder.toString()
     }
@@ -120,4 +136,16 @@
         }
         builder.append(indent).append("}\n")
     }
+
+    companion object {
+        const val TAG = "CatalystScreenTestCase"
+
+        fun dumpThreads() {
+            for ((thread, stack) in Thread.getAllStackTraces()) {
+                Log.i(TAG, "$thread")
+                for (frame in stack) Log.i(TAG, "  $frame")
+                Log.i(TAG, "")
+            }
+        }
+    }
 }
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/GroupSectionDividerMixin.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/GroupSectionDividerMixin.kt
new file mode 100644
index 0000000..ba5f5cf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/GroupSectionDividerMixin.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.settingslib.widget
+
+/**
+ * A base interface to indicate that a class should not have rounded corners.
+ *
+ * Classes implementing this interface will be treated as already handle rounded corners.
+ */
+interface GroupSectionDividerMixin
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
new file mode 100644
index 0000000..535d80f
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.settingslib.widget
+
+import androidx.preference.PreferenceFragmentCompat
+import androidx.preference.PreferenceScreen
+import androidx.recyclerview.widget.RecyclerView
+
+/** Base class for Settings to use PreferenceFragmentCompat */
+open abstract class SettingsBasePreferenceFragment : PreferenceFragmentCompat() {
+
+    override fun onCreateAdapter(preferenceScreen: PreferenceScreen): RecyclerView.Adapter<*> {
+        if (SettingsThemeHelper.isExpressiveTheme(requireContext()))
+            return SettingsPreferenceGroupAdapter(preferenceScreen)
+        return super.onCreateAdapter(preferenceScreen)
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt
new file mode 100644
index 0000000..98b7f76
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2024 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.settingslib.widget
+
+import android.os.Handler
+import android.os.Looper
+import androidx.annotation.DrawableRes
+import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
+import androidx.preference.PreferenceGroup
+import androidx.preference.PreferenceGroupAdapter
+import androidx.preference.PreferenceViewHolder
+import com.android.settingslib.widget.theme.R
+
+/**
+ * A custom adapter for displaying settings preferences in a list, handling rounded corners
+ * for preference items within a group.
+ */
+open class SettingsPreferenceGroupAdapter @JvmOverloads constructor(
+    preferenceGroup: PreferenceGroup
+) : PreferenceGroupAdapter(preferenceGroup) {
+
+    private val mPreferenceGroup = preferenceGroup
+    private var mRoundCornerMappingList: ArrayList<Int> = ArrayList()
+
+    private var mNormalPaddingStart = 0
+    private var mGroupPaddingStart = 0
+    private var mNormalPaddingEnd = 0
+    private var mGroupPaddingEnd = 0
+
+    private val mHandler = Handler(Looper.getMainLooper())
+
+    private val syncRunnable = Runnable { updatePreferences() }
+
+    init {
+        val context = preferenceGroup.context
+        mNormalPaddingStart =
+            context.resources.getDimensionPixelSize(R.dimen.settingslib_expressive_space_small1)
+        mGroupPaddingStart = mNormalPaddingStart * 2
+        mNormalPaddingEnd =
+            context.resources.getDimensionPixelSize(R.dimen.settingslib_expressive_space_small1)
+        mGroupPaddingEnd = mNormalPaddingEnd * 2
+        updatePreferences()
+    }
+
+    override fun onPreferenceHierarchyChange(preference: Preference) {
+        super.onPreferenceHierarchyChange(preference)
+
+        // Post after super class has posted their sync runnable to update preferences.
+        mHandler.removeCallbacks(syncRunnable)
+        mHandler.post(syncRunnable)
+    }
+
+    override fun onBindViewHolder(holder: PreferenceViewHolder, position: Int) {
+        super.onBindViewHolder(holder, position)
+        updateBackground(holder, position)
+    }
+
+    private fun updatePreferences() {
+        val oldList = ArrayList(mRoundCornerMappingList)
+        mRoundCornerMappingList = ArrayList()
+        mappingPreferenceGroup(mRoundCornerMappingList, mPreferenceGroup)
+        if (mRoundCornerMappingList != oldList) {
+            notifyDataSetChanged()
+        }
+    }
+
+    private fun mappingPreferenceGroup(cornerStyles: MutableList<Int>, group: PreferenceGroup) {
+        cornerStyles.clear()
+        cornerStyles.addAll(MutableList(itemCount) { 0 })
+
+        // the first item in to group
+        var startIndex = -1
+        // the last item in the group
+        var endIndex = -1
+        var currentParent: PreferenceGroup? = group
+        for (i in 0 until itemCount) {
+            when (val pref = getItem(i)) {
+                // the preference has round corner background, so we don't need to handle it.
+                is GroupSectionDividerMixin -> {
+                    cornerStyles[i] = 0
+                    startIndex = -1
+                    endIndex = -1
+                }
+
+                // PreferenceCategory should not have round corner background.
+                is PreferenceCategory -> {
+                    cornerStyles[i] = 0
+                    startIndex = -1
+                    endIndex = -1
+                    currentParent = pref
+                }
+
+                // ExpandablePreference is PreferenceGroup but it should handle round corner
+                is Expandable -> {
+                    // When ExpandablePreference is expanded, we treat is as the first item.
+                    if (pref.isExpanded()) {
+                        currentParent = pref as? PreferenceGroup
+                        startIndex = i
+                        cornerStyles[i] = cornerStyles[i] or ROUND_CORNER_TOP or ROUND_CORNER_CENTER
+                        endIndex = -1
+                    }
+                }
+
+                else -> {
+                    val parent = pref?.parent
+
+                    // item in the group should have round corner background.
+                    cornerStyles[i] = cornerStyles[i] or ROUND_CORNER_CENTER
+                    if (parent === currentParent) {
+                        // find the first item in the group
+                        if (startIndex == -1) {
+                            startIndex = i
+                            cornerStyles[i] = cornerStyles[i] or ROUND_CORNER_TOP
+                        }
+
+                        // find the last item in the group, if we find the new last item, we should
+                        // remove the old last item round corner.
+                        if (endIndex == -1 || endIndex < i) {
+                            if (endIndex != -1) {
+                                cornerStyles[endIndex] =
+                                    cornerStyles[endIndex] and ROUND_CORNER_BOTTOM.inv()
+                            }
+                            endIndex = i
+                            cornerStyles[i] = cornerStyles[i] or ROUND_CORNER_BOTTOM
+                        }
+                    } else {
+                        // this item is new group, we should reset the index.
+                        currentParent = parent
+                        startIndex = i
+                        cornerStyles[i] = cornerStyles[i] or ROUND_CORNER_TOP
+                        endIndex = i
+                        cornerStyles[i] = cornerStyles[i] or ROUND_CORNER_BOTTOM
+                    }
+                }
+            }
+        }
+    }
+
+    /** handle roundCorner background  */
+    private fun updateBackground(holder: PreferenceViewHolder, position: Int) {
+        @DrawableRes val backgroundRes = getRoundCornerDrawableRes(position, false /* isSelected*/)
+
+        val v = holder.itemView
+        val paddingStart = if (backgroundRes == 0) mNormalPaddingStart else mGroupPaddingStart
+        val paddingEnd = if (backgroundRes == 0) mNormalPaddingEnd else mGroupPaddingEnd
+
+        v.setPaddingRelative(paddingStart, v.paddingTop, paddingEnd, v.paddingBottom)
+        v.setBackgroundResource(backgroundRes)
+    }
+
+    @DrawableRes
+    protected fun getRoundCornerDrawableRes(position: Int, isSelected: Boolean): Int {
+        val cornerType = mRoundCornerMappingList[position]
+
+        if ((cornerType and ROUND_CORNER_CENTER) == 0) {
+            return 0
+        }
+
+        return when {
+            (cornerType and ROUND_CORNER_TOP) != 0 && (cornerType and ROUND_CORNER_BOTTOM) == 0 -> {
+                // the first
+                if (isSelected) R.drawable.settingslib_round_background_top_selected
+                else R.drawable.settingslib_round_background_top
+            }
+
+            (cornerType and ROUND_CORNER_BOTTOM) != 0 && (cornerType and ROUND_CORNER_TOP) == 0 -> {
+                // the last
+                if (isSelected) R.drawable.settingslib_round_background_bottom_selected
+                else R.drawable.settingslib_round_background_bottom
+            }
+
+            (cornerType and ROUND_CORNER_TOP) != 0 && (cornerType and ROUND_CORNER_BOTTOM) != 0 -> {
+                // the only one preference
+                if (isSelected) R.drawable.settingslib_round_background_selected
+                else R.drawable.settingslib_round_background
+            }
+
+            else -> {
+                // in the center
+                if (isSelected) R.drawable.settingslib_round_background_center_selected
+                else R.drawable.settingslib_round_background_center
+            }
+        }
+    }
+
+    companion object {
+        private const val ROUND_CORNER_CENTER: Int = 1
+        private const val ROUND_CORNER_TOP: Int = 1 shl 1
+        private const val ROUND_CORNER_BOTTOM: Int = 1 shl 2
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
index b69912a..73d0bec 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -29,7 +29,7 @@
 
 allprojects {
     extra["androidTop"] = androidTop
-    extra["jetpackComposeVersion"] = "1.7.0"
+    extra["jetpackComposeVersion"] = "1.7.3"
 }
 
 subprojects {
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 8f8275b..914f06c 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -54,7 +54,7 @@
 dependencies {
     api(project(":SettingsLibColor"))
     api("androidx.appcompat:appcompat:1.7.0")
-    api("androidx.compose.material3:material3:1.3.0")
+    api("androidx.compose.material3:material3:1.4.0-alpha01")
     api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
     api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
     api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 2c55779..693fb35 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -46,6 +46,7 @@
 import androidx.compose.material3.TopAppBarState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.NonRestartableComposable
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.derivedStateOf
@@ -326,6 +327,9 @@
     // Sets the app bar's height offset limit to hide just the bottom title area and keep top title
     // visible when collapsed.
     scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.floatValue
+    if (isSpaExpressiveEnabled) {
+        LaunchedEffect(scrollBehavior?.state?.heightOffsetLimit) { scrollBehavior?.collapse() }
+    }
 
     // Obtain the container Color from the TopAppBarColors using the `collapsedFraction`, as the
     // bottom part of this TwoRowsTopAppBar changes color at the same rate the app bar expands or
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
index 7d8ee79..60b1e639 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
@@ -39,7 +39,6 @@
 import com.android.settingslib.spa.framework.compose.horizontalValues
 import com.android.settingslib.spa.framework.compose.verticalValues
 import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
 import com.android.settingslib.spa.framework.theme.settingsBackground
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -56,9 +55,6 @@
 ) {
     ActivityTitle(title)
     val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
-    if (isSpaExpressiveEnabled) {
-        LaunchedEffect(scrollBehavior.state.heightOffsetLimit) { scrollBehavior.collapse() }
-    }
 
     Scaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
diff --git a/packages/SettingsLib/ZeroStatePreference/src/com/android/settingslib/widget/ZeroStatePreference.kt b/packages/SettingsLib/ZeroStatePreference/src/com/android/settingslib/widget/ZeroStatePreference.kt
index 9b1ccef..62573fe 100644
--- a/packages/SettingsLib/ZeroStatePreference/src/com/android/settingslib/widget/ZeroStatePreference.kt
+++ b/packages/SettingsLib/ZeroStatePreference/src/com/android/settingslib/widget/ZeroStatePreference.kt
@@ -32,7 +32,7 @@
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0,
     defStyleRes: Int = 0
-) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
 
     private val iconTint: Int = context.getColor(
         com.android.settingslib.widget.theme.R.color.settingslib_materialColorOnSecondaryContainer
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 79c3ff9..5a8763f 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -149,3 +149,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "audio_sharing_developer_option"
+    namespace: "cross_device_experiences"
+    description: "Gates whether to enable audio sharing developer option"
+    bug: "368401233"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 739c7d6..abc58ee 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1640,13 +1640,13 @@
     <string name="media_transfer_wired_headphone_name">Wired headphone</string>
 
     <!-- Name of the 3.5mm headphone, used in desktop devices. [CHAR LIMIT=50] -->
-    <string name="media_transfer_headphone_name">Headphone</string>
+    <string name="media_transfer_headphone_name">Wired audio</string>
 
     <!-- Name of the usb audio device speaker, used in desktop devices. [CHAR LIMIT=50] -->
     <string name="media_transfer_usb_audio_name">USB audio</string>
 
     <!-- Name of the 3.5mm audio device mic. [CHAR LIMIT=50] -->
-    <string name="media_transfer_wired_device_mic_name">Mic jack</string>
+    <string name="media_transfer_wired_device_mic_name">Wired microphone</string>
 
     <!-- Name of the usb audio device mic. [CHAR LIMIT=50] -->
     <string name="media_transfer_usb_device_mic_name">USB microphone</string>
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 1a99d25..65b2275 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -39,6 +39,7 @@
         "configinfra_framework_flags_java_lib",
         "device_config_service_flags_java",
         "libaconfig_java_proto_lite",
+        "notification_flags_lib",
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibDisplayUtils",
     ],
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 6c31831..ebeee85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -29,6 +29,7 @@
 import android.icu.util.ULocale;
 import android.media.AudioManager;
 import android.media.RingtoneManager;
+import android.media.Utils;
 import android.net.Uri;
 import android.os.LocaleList;
 import android.os.RemoteException;
@@ -309,6 +310,13 @@
                     return SILENT_RINGTONE;
                 }
             } else {
+                // If the ringtone/notification support the vibration, use the original value.
+                final int ringtoneType = getRingtoneType(name);
+                if ((ringtoneType == RingtoneManager.TYPE_RINGTONE
+                        || ringtoneType == RingtoneManager.TYPE_NOTIFICATION)
+                        && hasVibrationSettings(value, ringtoneType)) {
+                    return value;
+                }
                 return getCanonicalRingtoneValue(value);
             }
         }
@@ -362,6 +370,15 @@
             return;
         }
 
+        // If the ringtone/notification has vibration, we backup original value in onBackupValue.
+        // So use the value directly for restoring.
+        if ((ringtoneType == RingtoneManager.TYPE_RINGTONE
+                || ringtoneType == RingtoneManager.TYPE_NOTIFICATION)
+                && hasVibrationSettings(value, ringtoneType)) {
+            RingtoneManager.setActualDefaultRingtoneUri(mContext, ringtoneType, Uri.parse(value));
+            return;
+        }
+
         Uri ringtoneUri = null;
         try {
             ringtoneUri =
@@ -617,6 +634,19 @@
         return allLocales.remove(toFullLocale(filteredLocale));
     }
 
+    private boolean hasVibrationSettings(String value, int type) {
+        if (Utils.hasVibration(Uri.parse(value)) && mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported)) {
+            if (type == RingtoneManager.TYPE_RINGTONE) {
+                return android.media.audio.Flags.enableRingtoneHapticsCustomization();
+            }
+            if (type == RingtoneManager.TYPE_NOTIFICATION) {
+                return com.android.server.notification.Flags.notificationVibrationInSoundUri();
+            }
+        }
+        return false;
+    }
+
     /**
      * Sets the locale specified. Input data is the byte representation of comma separated
      * multiple BCP-47 language tags. For backwards compatibility, strings of the form
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index 4b10b56..cea2bbc 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -37,9 +37,12 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.media.AudioManager;
+import android.media.Utils;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.LocaleList;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.BaseColumns;
 import android.provider.MediaStore;
 import android.provider.Settings;
@@ -54,8 +57,11 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -63,6 +69,7 @@
  * Tests for the SettingsHelperTest
  */
 @RunWith(AndroidJUnit4.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class SettingsHelperTest {
     private static final String SETTING_KEY = "setting_key";
     private static final String SETTING_VALUE = "setting_value";
@@ -74,9 +81,13 @@
             "content://media/internal/audio/media/20?title=DefaultNotification&canonical=1";
     private static final String DEFAULT_ALARM_VALUE =
             "content://media/internal/audio/media/30?title=DefaultAlarm&canonical=1";
+    private static final String VIBRATION_FILE_NAME = "haptics.xml";
 
     private SettingsHelper mSettingsHelper;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock private Context mContext;
     @Mock private Resources mResources;
     @Mock private AudioManager mAudioManager;
@@ -120,6 +131,22 @@
     }
 
     @Test
+    @EnableFlags({android.media.audio.Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION,
+            com.android.server.notification.Flags.FLAG_NOTIFICATION_VIBRATION_IN_SOUND_URI})
+    public void testOnBackupValue_ringtoneVibrationSupport_returnsSameValue() {
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported)).thenReturn(
+                true);
+        String testRingtoneVibrationValue = createUriWithVibration(DEFAULT_RINGTONE_VALUE);
+        String testNotificationVibrationValue = createUriWithVibration(DEFAULT_NOTIFICATION_VALUE);
+
+        assertEquals(testRingtoneVibrationValue, mSettingsHelper.onBackupValue(
+                Settings.System.RINGTONE, testRingtoneVibrationValue));
+        assertEquals(testNotificationVibrationValue, mSettingsHelper.onBackupValue(
+                Settings.System.NOTIFICATION_SOUND, testNotificationVibrationValue));
+    }
+
+    @Test
     public void testGetRealValue_settingNotReplaced_returnsSameValue() {
         when(mSettingsHelper.isReplacedSystemSetting(eq(SETTING_KEY))).thenReturn(false);
 
@@ -675,6 +702,30 @@
                 .isEqualTo(null);
     }
 
+    @Test
+    @EnableFlags({android.media.audio.Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION,
+            com.android.server.notification.Flags.FLAG_NOTIFICATION_VIBRATION_IN_SOUND_URI})
+    public void testRestoreValue_ringtoneVibrationSupport_restoreValue() {
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported)).thenReturn(
+                true);
+        String testRingtoneVibrationValue = createUriWithVibration(DEFAULT_RINGTONE_VALUE);
+        String testNotificationVibrationValue = createUriWithVibration(DEFAULT_NOTIFICATION_VALUE);
+        ContentProvider mockMediaContentProvider =
+                new MockContentProvider(mContext) {
+                    @Override
+                    public String getType(Uri url) {
+                        return "audio/ogg";
+                    }
+                };
+        mContentResolver.addProvider(MediaStore.AUTHORITY, mockMediaContentProvider);
+        resetRingtoneSettingsToDefault();
+
+        assertRingtoneSettingsRestoring(Settings.System.RINGTONE, testRingtoneVibrationValue);
+        assertRingtoneSettingsRestoring(
+                Settings.System.NOTIFICATION_SOUND, testNotificationVibrationValue);
+    }
+
     private static class MockSettingsProvider extends MockContentProvider {
         private final ArrayMap<String, String> mKeyValueStore = new ArrayMap<>();
         MockSettingsProvider(Context context) {
@@ -766,4 +817,25 @@
         assertThat(Settings.System.getString(mContentResolver, Settings.System.ALARM_ALERT))
                 .isEqualTo(DEFAULT_ALARM_VALUE);
     }
+
+    private String createUriWithVibration(String defaultUriString) {
+        return Uri.parse(defaultUriString).buildUpon()
+                .appendQueryParameter(
+                        Utils.VIBRATION_URI_PARAM, VIBRATION_FILE_NAME).build().toString();
+    }
+
+    private void assertRingtoneSettingsRestoring(
+            String settings, String testRingtoneSettingsValue) {
+        mSettingsHelper.restoreValue(
+                mContext,
+                mContentResolver,
+                new ContentValues(),
+                Uri.EMPTY,
+                settings,
+                testRingtoneSettingsValue,
+                0);
+
+        assertThat(Settings.System.getString(mContentResolver, settings))
+                .isEqualTo(testRingtoneSettingsValue);
+    }
 }
diff --git a/packages/StatementService/Parser/Android.bp b/packages/StatementService/Parser/Android.bp
new file mode 100644
index 0000000..c8af134
--- /dev/null
+++ b/packages/StatementService/Parser/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2024 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 {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+    name: "StatementServiceParser",
+    use_resource_processor: true,
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+    target_sdk_version: "29",
+}
diff --git a/packages/StatementService/Parser/AndroidManifest.xml b/packages/StatementService/Parser/AndroidManifest.xml
new file mode 100644
index 0000000..a3a99ac
--- /dev/null
+++ b/packages/StatementService/Parser/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.statementservice.parser">
+</manifest>
\ No newline at end of file
diff --git a/packages/StatementService/Parser/src/com/android/statementservice/parser/DalComponentParser.kt b/packages/StatementService/Parser/src/com/android/statementservice/parser/DalComponentParser.kt
new file mode 100644
index 0000000..4314f86
--- /dev/null
+++ b/packages/StatementService/Parser/src/com/android/statementservice/parser/DalComponentParser.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+@file:JvmName("DalComponentParser")
+
+package com.android.statementservice.parser
+
+import android.os.PatternMatcher.PATTERN_ADVANCED_GLOB
+import android.os.PatternMatcher.PATTERN_LITERAL
+import android.os.PatternMatcher.PATTERN_PREFIX
+import android.os.PatternMatcher.PATTERN_SIMPLE_GLOB
+
+/**
+ * Parses a DAL component matching expression to Android's {@link android.os.PatternMatcher} type
+ * and pattern. Matching expressions support the following wildcards:
+ *
+ *  1) An asterisk (*) matches zero to as many characters as possible
+ *  2) A question mark (?) matches any single character.
+ *
+ * Matching one to many characters can be done with a question mark followed by an asterisk (?+).
+ *
+ * @param expression A matching expression string from a DAL relation extension component used for
+ *                   matching a URI part. This must be a non-empty string and all characters in the
+ *                   string should be decoded.
+ *
+ * @return Returns a Pair containing a {@link android.os.PatternMatcher} type and pattern.
+ */
+fun parseMatchingExpression(expression: String): Pair<Int, String> {
+    if (expression.isNullOrEmpty()) {
+        throw IllegalArgumentException("Matching expressions cannot be an empty string")
+    }
+    var count = 0
+    var isAdvanced = expression.contains("?*")
+    val pattern = buildString {
+        for (char in expression) {
+            when (char) {
+                '*' -> {
+                    if (this.endsWith('.') && !this.endsWith("\\.")) {
+                        append('+')
+                    } else {
+                        count += 1
+                        append(".*")
+                    }
+                }
+                '?' -> {
+                    count += 1
+                    append('.')
+                }
+                '.' -> {
+                    append("\\.")
+                }
+                '[', ']', '{', '}' -> {
+                    if (isAdvanced) {
+                        append('\\')
+                    }
+                    append(char)
+                }
+                else -> append(char)
+            }
+        }
+    }
+    if (count == 0) {
+        return Pair(PATTERN_LITERAL, pattern)
+    }
+    if (count == 1 && pattern.endsWith(".*")) {
+        return Pair(PATTERN_PREFIX, pattern.dropLast(2))
+    }
+    if (isAdvanced) {
+        return Pair(PATTERN_ADVANCED_GLOB, pattern)
+    }
+    return Pair(PATTERN_SIMPLE_GLOB, pattern)
+}
\ No newline at end of file
diff --git a/packages/StatementService/TEST_MAPPING b/packages/StatementService/TEST_MAPPING
new file mode 100644
index 0000000..0714c93
--- /dev/null
+++ b/packages/StatementService/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit" : [
+    {
+      "name": "StatementServiceTests"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/StatementService/tests/Android.bp b/packages/StatementService/tests/Android.bp
new file mode 100644
index 0000000..ec1bd96
--- /dev/null
+++ b/packages/StatementService/tests/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2024 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 {
+    default_applicable_licenses: ["frameworks_base_license"],
+    default_team: "trendy_team_framework_android_packages",
+}
+
+android_test {
+    name: "StatementServiceTests",
+    use_resource_processor: true,
+    test_suites: ["general-tests"],
+    srcs: ["src/**/*.kt"],
+    static_libs: [
+        "androidx.test.ext.junit",
+        "androidx.test.runner",
+        "StatementServiceParser",
+        "truth",
+    ],
+}
diff --git a/packages/StatementService/tests/AndroidManifest.xml b/packages/StatementService/tests/AndroidManifest.xml
new file mode 100644
index 0000000..bde0f95
--- /dev/null
+++ b/packages/StatementService/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.statementservice.test">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.statementservice.test" />
+</manifest>
diff --git a/packages/StatementService/tests/src/com/android/statementservice/parser/DalComponentParserTest.kt b/packages/StatementService/tests/src/com/android/statementservice/parser/DalComponentParserTest.kt
new file mode 100644
index 0000000..44a56ec
--- /dev/null
+++ b/packages/StatementService/tests/src/com/android/statementservice/parser/DalComponentParserTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 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.statementservice.parser
+
+import android.os.PatternMatcher.PATTERN_ADVANCED_GLOB
+import android.os.PatternMatcher.PATTERN_LITERAL
+import android.os.PatternMatcher.PATTERN_PREFIX
+import android.os.PatternMatcher.PATTERN_SIMPLE_GLOB
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class DalComponentParserTest {
+
+    @Test
+    fun parseExpressions() {
+        validateParsedExpression("foobar", PATTERN_LITERAL, "foobar")
+        validateParsedExpression("foo.bar", PATTERN_LITERAL, "foo\\.bar")
+        validateParsedExpression("foo*", PATTERN_PREFIX, "foo")
+        validateParsedExpression("*bar", PATTERN_SIMPLE_GLOB, ".*bar")
+        validateParsedExpression("foo*bar", PATTERN_SIMPLE_GLOB, "foo.*bar")
+        validateParsedExpression("foo.*bar", PATTERN_SIMPLE_GLOB, "foo\\..*bar")
+        validateParsedExpression("*foo*bar", PATTERN_SIMPLE_GLOB, ".*foo.*bar")
+        validateParsedExpression("foo?bar", PATTERN_SIMPLE_GLOB, "foo.bar")
+        validateParsedExpression("foo.?bar", PATTERN_SIMPLE_GLOB, "foo\\..bar")
+        validateParsedExpression("?bar", PATTERN_SIMPLE_GLOB, ".bar")
+        validateParsedExpression("foo?", PATTERN_SIMPLE_GLOB, "foo.")
+        validateParsedExpression("fo?b*r", PATTERN_SIMPLE_GLOB, "fo.b.*r")
+        validateParsedExpression("?*bar", PATTERN_ADVANCED_GLOB, ".+bar")
+        validateParsedExpression("foo?*bar", PATTERN_ADVANCED_GLOB, "foo.+bar")
+        validateParsedExpression("foo?*bar*", PATTERN_ADVANCED_GLOB, "foo.+bar.*")
+        validateParsedExpression("foo*?bar", PATTERN_SIMPLE_GLOB, "foo.*.bar")
+
+        // set matches are not supported in DAL
+        validateParsedExpression("foo[a-z]", PATTERN_LITERAL, "foo[a-z]")
+        validateParsedExpression("foo[a-z]+", PATTERN_LITERAL, "foo[a-z]+")
+        validateParsedExpression("foo[a-z]*", PATTERN_PREFIX, "foo[a-z]")
+        validateParsedExpression("[a-z]*bar", PATTERN_SIMPLE_GLOB, "[a-z].*bar")
+        validateParsedExpression("foo[a-z]?bar", PATTERN_SIMPLE_GLOB, "foo[a-z].bar")
+        validateParsedExpression("foo[a-z]?*bar", PATTERN_ADVANCED_GLOB, "foo\\[a-z\\].+bar")
+
+        // range matches are not supported in DAL
+        validateParsedExpression("fo{2}", PATTERN_LITERAL, "fo{2}")
+        validateParsedExpression("fo{2}+", PATTERN_LITERAL, "fo{2}+")
+        validateParsedExpression("fo{2}*", PATTERN_PREFIX, "fo{2}")
+        validateParsedExpression("fo{2}*bar", PATTERN_SIMPLE_GLOB, "fo{2}.*bar")
+        validateParsedExpression("fo{2}?*", PATTERN_ADVANCED_GLOB, "fo\\{2\\}.+")
+        validateParsedExpression("foo{2}?*bar", PATTERN_ADVANCED_GLOB, "foo\\{2\\}.+bar")
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun parseEmptyExpression() {
+        parseMatchingExpression("")
+    }
+
+    private fun validateParsedExpression(given: String, expectedType: Int, expectedFilter: String) {
+        val (type, filter) = parseMatchingExpression(given)
+        assertThat(filter).isEqualTo(expectedFilter)
+        assertThat(type).isEqualTo(expectedType)
+        assertThat(filter).isEqualTo(expectedFilter)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2863531..d7b9683 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -899,9 +899,9 @@
         "androidx.compose.runtime_runtime",
     ],
     libs: [
-        "android.test.runner.stubs.system",
-        "android.test.base.stubs.system",
-        "android.test.mock.stubs.system",
+        "android.test.runner.impl",
+        "android.test.base.impl",
+        "android.test.mock.impl",
         "truth",
     ],
 
@@ -936,9 +936,9 @@
         "androidx.compose.runtime_runtime",
     ],
     libs: [
-        "android.test.runner.stubs.system",
-        "android.test.base.stubs.system",
-        "android.test.mock.stubs.system",
+        "android.test.runner.impl",
+        "android.test.base.impl",
+        "android.test.mock.impl",
         "truth",
     ],
 
@@ -974,9 +974,9 @@
         "androidx.compose.runtime_runtime",
     ],
     libs: [
-        "android.test.runner.stubs.system",
-        "android.test.base.stubs.system",
-        "android.test.mock.stubs.system",
+        "android.test.runner.impl",
+        "android.test.base.impl",
+        "android.test.mock.impl",
     ],
     auto_gen_config: true,
     plugins: [
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a21a805..c79c044 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -395,9 +395,9 @@
 }
 
 flag {
-    name: "status_bar_ron_chips"
+    name: "status_bar_notification_chips"
     namespace: "systemui"
-    description: "Show rich ongoing notifications as chips in the status bar"
+    description: "Show promoted ongoing notifications as chips in the status bar"
     bug: "361346412"
 }
 
@@ -1481,3 +1481,9 @@
    bug: "370863642"
 }
 
+flag {
+  name: "notes_role_qs_tile"
+  namespace: "systemui"
+  description: "Enables notes role qs tile which opens default notes role app in app bubbles"
+  bug: "357863750"
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index 93a99bd..18f40c9 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -136,20 +136,16 @@
             )
 
         /**
-         * The timings when animating a View into an app using a spring animator.
-         *
-         * Important: since springs don't have fixed durations, these timings represent fractions of
-         * the progress between the spring's initial value and its final value.
-         *
-         * TODO(b/372858592): make this a separate class explicitly using percentages.
+         * The timings when animating a View into an app using a spring animator. These timings
+         * represent fractions of the progress between the spring's initial value and its final
+         * value.
          */
         val SPRING_TIMINGS =
-            TransitionAnimator.Timings(
-                totalDuration = 1000L,
-                contentBeforeFadeOutDelay = 0L,
-                contentBeforeFadeOutDuration = 800L,
-                contentAfterFadeInDelay = 850L,
-                contentAfterFadeInDuration = 135L,
+            TransitionAnimator.SpringTimings(
+                contentBeforeFadeOutDelay = 0f,
+                contentBeforeFadeOutDuration = 0.8f,
+                contentAfterFadeInDelay = 0.85f,
+                contentAfterFadeInDuration = 0.135f,
             )
 
         /**
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index 1d8ff77..9dc9348 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -52,7 +52,7 @@
     private val interpolators: Interpolators,
 
     /** [springTimings] and [springInterpolators] must either both be null or both not null. */
-    private val springTimings: Timings? = null,
+    private val springTimings: SpringTimings? = null,
     private val springInterpolators: Interpolators? = null,
     private val springParams: SpringParams = DEFAULT_SPRING_PARAMS,
 ) {
@@ -83,8 +83,22 @@
             delay: Long,
             duration: Long,
         ): Float {
+            return getProgressInternal(
+                timings.totalDuration.toFloat(),
+                linearProgress,
+                delay.toFloat(),
+                duration.toFloat(),
+            )
+        }
+
+        private fun getProgressInternal(
+            totalDuration: Float,
+            linearProgress: Float,
+            delay: Float,
+            duration: Float,
+        ): Float {
             return MathUtils.constrain(
-                (linearProgress * timings.totalDuration - delay) / duration,
+                (linearProgress * totalDuration - delay) / duration,
                 0.0f,
                 1.0f,
             )
@@ -367,6 +381,25 @@
         val contentAfterFadeInDuration: Long,
     )
 
+    /**
+     * The timings (durations and delays) used by the multi-spring animator. These are expressed as
+     * fractions of 1, similar to how the progress of an animator can be expressed as a float value
+     * between 0 and 1.
+     */
+    class SpringTimings(
+        /** The portion of animation to wait before fading out the expanding content. */
+        val contentBeforeFadeOutDelay: Float,
+
+        /** The portion of animation during which the expanding content fades out. */
+        val contentBeforeFadeOutDuration: Float,
+
+        /** The portion of animation to wait before fading in the expanded content. */
+        val contentAfterFadeInDelay: Float,
+
+        /** The portion of animation during which the expanded content fades in. */
+        val contentAfterFadeInDuration: Float,
+    )
+
     /** The interpolators used by this animator. */
     data class Interpolators(
         /** The interpolator used for the Y position, width, height and corner radius. */
@@ -576,18 +609,14 @@
                 }
 
                 override fun onAnimationEnd(animation: Animator) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Animation ended")
-                    }
-
-                    // TODO(b/330672236): Post this to the main thread instead so that it does not
-                    // flicker with Flexiglass enabled.
-                    controller.onTransitionAnimationEnd(isExpandingFullyAbove)
-                    transitionContainerOverlay.remove(windowBackgroundLayer)
-
-                    if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) {
-                        openingWindowSyncViewOverlay?.remove(windowBackgroundLayer)
-                    }
+                    onAnimationEnd(
+                        controller,
+                        isExpandingFullyAbove,
+                        windowBackgroundLayer,
+                        transitionContainerOverlay,
+                        openingWindowSyncViewOverlay,
+                        moveBackgroundLayerWhenAppVisibilityChanges,
+                    )
                 }
             }
         )
@@ -1021,34 +1050,47 @@
         cornerRadii[7] = state.bottomCornerRadius
         drawable.cornerRadii = cornerRadii
 
-        val timings: Timings
         val interpolators: Interpolators
+        val fadeInProgress: Float
+        val fadeOutProgress: Float
         if (useSpring) {
-            timings = springTimings!!
             interpolators = springInterpolators!!
+            val timings = springTimings!!
+            fadeInProgress =
+                getProgressInternal(
+                    totalDuration = 1f,
+                    linearProgress,
+                    timings.contentBeforeFadeOutDelay,
+                    timings.contentBeforeFadeOutDuration,
+                )
+            fadeOutProgress =
+                getProgressInternal(
+                    totalDuration = 1f,
+                    linearProgress,
+                    timings.contentAfterFadeInDelay,
+                    timings.contentAfterFadeInDuration,
+                )
         } else {
-            timings = this.timings
             interpolators = this.interpolators
+            fadeInProgress =
+                getProgress(
+                    timings,
+                    linearProgress,
+                    timings.contentBeforeFadeOutDelay,
+                    timings.contentBeforeFadeOutDuration,
+                )
+            fadeOutProgress =
+                getProgress(
+                    timings,
+                    linearProgress,
+                    timings.contentAfterFadeInDelay,
+                    timings.contentAfterFadeInDuration,
+                )
         }
 
         // We first fade in the background layer to hide the expanding view, then fade it out with
         // SRC mode to draw a hole punch in the status bar and reveal the opening window (if
         // needed). If !isLaunching, the reverse happens.
-        val fadeInProgress =
-            getProgress(
-                timings,
-                linearProgress,
-                timings.contentBeforeFadeOutDelay,
-                timings.contentBeforeFadeOutDuration,
-            )
-        val fadeOutProgress =
-            getProgress(
-                timings,
-                linearProgress,
-                timings.contentAfterFadeInDelay,
-                timings.contentAfterFadeInDuration,
-            )
-
         if (isLaunching) {
             if (fadeInProgress < 1) {
                 val alpha =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 96c47cc..4ab5261 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -765,7 +765,7 @@
                     alpha = { outlineAlpha },
                     modifier =
                         Modifier.requiredSize(dpSize).thenIf(
-                            dragDropState.draggingItemIndex != index
+                            dragDropState.draggingItemKey != item.key
                         ) {
                             Modifier.animateItem(
                                 placementSpec = spring(stiffness = Spring.StiffnessMediumLow)
@@ -778,7 +778,7 @@
                         dragDropState = dragDropState,
                         selected = selected,
                         enabled = item.isWidgetContent(),
-                        index = index,
+                        key = item.key,
                     ) { isDragging ->
                         CommunalContent(
                             modifier = Modifier.fillMaxSize(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 101385f..0718bc3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -38,8 +38,9 @@
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
 import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.round
 import androidx.compose.ui.unit.toOffset
 import androidx.compose.ui.unit.toSize
 import com.android.systemui.Flags.communalWidgetResizing
@@ -93,7 +94,7 @@
     private val scope: CoroutineScope,
     private val updateDragPositionForRemove: (offset: Offset) -> Boolean,
 ) {
-    var draggingItemIndex by mutableStateOf<Int?>(null)
+    var draggingItemKey by mutableStateOf<Any?>(null)
         private set
 
     var isDraggingToRemove by mutableStateOf(false)
@@ -105,6 +106,8 @@
     private var draggingItemInitialOffset by mutableStateOf(Offset.Zero)
     private var dragStartPointerOffset by mutableStateOf(Offset.Zero)
 
+    private var previousTargetItemKey: Any? = null
+
     internal val draggingItemOffset: Offset
         get() =
             draggingItemLayoutInfo?.let { item ->
@@ -112,7 +115,7 @@
             } ?: Offset.Zero
 
     private val draggingItemLayoutInfo: LazyGridItemInfo?
-        get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggingItemIndex }
+        get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.key == draggingItemKey }
 
     /**
      * Called when dragging is initiated.
@@ -137,7 +140,7 @@
             .firstItemAtOffset(normalizedOffset - contentOffset)
             ?.apply {
                 dragStartPointerOffset = normalizedOffset - this.offset.toOffset()
-                draggingItemIndex = index
+                draggingItemKey = key
                 draggingItemInitialOffset = this.offset.toOffset()
                 return true
             }
@@ -146,16 +149,19 @@
     }
 
     internal fun onDragInterrupted() {
-        draggingItemIndex?.let {
+        draggingItemKey?.let {
             if (isDraggingToRemove) {
-                contentListState.onRemove(it)
+                contentListState.onRemove(
+                    contentListState.list.indexOfFirst { it.key == draggingItemKey }
+                )
                 isDraggingToRemove = false
                 updateDragPositionForRemove(Offset.Zero)
             }
             // persist list editing changes on dragging ends
             contentListState.onSaveList()
-            draggingItemIndex = null
+            draggingItemKey = null
         }
+        previousTargetItemKey = null
         draggingItemDraggedDelta = Offset.Zero
         draggingItemInitialOffset = Offset.Zero
         dragStartPointerOffset = Offset.Zero
@@ -170,15 +176,29 @@
         val startOffset = draggingItem.offset.toOffset() + draggingItemOffset
         val endOffset = startOffset + draggingItem.size.toSize()
         val middleOffset = startOffset + (endOffset - startOffset) / 2f
+        val draggingBoundingBox =
+            IntRect(draggingItem.offset + draggingItemOffset.round(), draggingItem.size)
 
         val targetItem =
-            state.layoutInfo.visibleItemsInfo
-                .asSequence()
-                .filter { item -> contentListState.isItemEditable(item.index) }
-                .filter { item -> draggingItem.index != item.index }
-                .firstItemAtOffset(middleOffset)
+            if (communalWidgetResizing()) {
+                state.layoutInfo.visibleItemsInfo.findLast { item ->
+                    val itemBoundingBox = IntRect(item.offset, item.size)
+                    draggingItemKey != item.key &&
+                        contentListState.isItemEditable(item.index) &&
+                        draggingBoundingBox.contains(itemBoundingBox.center)
+                }
+            } else {
+                state.layoutInfo.visibleItemsInfo
+                    .asSequence()
+                    .filter { item -> contentListState.isItemEditable(item.index) }
+                    .filter { item -> draggingItem.index != item.index }
+                    .firstItemAtOffset(middleOffset)
+            }
 
-        if (targetItem != null) {
+        if (
+            targetItem != null &&
+                (!communalWidgetResizing() || targetItem.key != previousTargetItemKey)
+        ) {
             val scrollToIndex =
                 if (targetItem.index == state.firstVisibleItemIndex) {
                     draggingItem.index
@@ -187,6 +207,14 @@
                 } else {
                     null
                 }
+            if (communalWidgetResizing()) {
+                // Keep track of the previous target item, to avoid rapidly oscillating between
+                // items if the target item doesn't visually move as a result of the index change.
+                // In this case, even after the index changes, we'd still be colliding with the
+                // element, so it would be selected as the target item the next time this function
+                // runs again, which would trigger us to revert the index change we recently made.
+                previousTargetItemKey = targetItem.key
+            }
             if (scrollToIndex != null) {
                 scope.launch {
                     // this is needed to neutralize automatic keeping the first item first.
@@ -196,20 +224,17 @@
             } else {
                 contentListState.onMove(draggingItem.index, targetItem.index)
             }
-            draggingItemIndex = targetItem.index
             isDraggingToRemove = false
-        } else {
+        } else if (targetItem == null) {
             val overscroll = checkForOverscroll(startOffset, endOffset)
             if (overscroll != 0f) {
                 scrollChannel.trySend(overscroll)
             }
             isDraggingToRemove = checkForRemove(startOffset)
+            previousTargetItemKey = null
         }
     }
 
-    private val LazyGridItemInfo.offsetEnd: IntOffset
-        get() = this.offset + this.size
-
     /** Calculate the amount dragged out of bound on both sides. Returns 0f if not overscrolled */
     private fun checkForOverscroll(startOffset: Offset, endOffset: Offset): Float {
         return when {
@@ -237,7 +262,7 @@
     viewModel: BaseCommunalViewModel,
 ): Modifier {
     return this.then(
-        pointerInput(dragDropState, contentOffset) {
+        Modifier.pointerInput(dragDropState, contentOffset) {
             detectDragGesturesAfterLongPress(
                 onDrag = { change, offset ->
                     change.consume()
@@ -273,7 +298,7 @@
 @Composable
 fun LazyGridItemScope.DraggableItem(
     dragDropState: GridDragDropState,
-    index: Int,
+    key: Any,
     enabled: Boolean,
     selected: Boolean,
     modifier: Modifier = Modifier,
@@ -283,7 +308,7 @@
         return content(false)
     }
 
-    val dragging = index == dragDropState.draggingItemIndex
+    val dragging = key == dragDropState.draggingItemKey
     val itemAlpha: Float by
         animateFloatAsState(
             targetValue = if (dragDropState.isDraggingToRemove) 0.5f else 1f,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index a525f36..9390664 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -30,14 +30,10 @@
 import androidx.compose.ui.viewinterop.AndroidView
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
-import com.android.keyguard.LockIconView
-import com.android.keyguard.LockIconViewController
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
 import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
@@ -61,7 +57,6 @@
     private val windowManager: WindowManager,
     private val authController: AuthController,
     private val featureFlags: FeatureFlagsClassic,
-    private val lockIconViewController: Lazy<LockIconViewController>,
     private val deviceEntryIconViewModel: Lazy<DeviceEntryIconViewModel>,
     private val deviceEntryForegroundViewModel: Lazy<DeviceEntryForegroundViewModel>,
     private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
@@ -71,42 +66,28 @@
 ) {
     @Composable
     fun SceneScope.LockIcon(overrideColor: Color? = null, modifier: Modifier = Modifier) {
-        if (!KeyguardBottomAreaRefactor.isEnabled && !DeviceEntryUdfpsRefactor.isEnabled) {
-            return
-        }
-
         val context = LocalContext.current
 
         AndroidView(
             factory = { context ->
-                val view =
-                    if (DeviceEntryUdfpsRefactor.isEnabled) {
-                        DeviceEntryIconView(
-                                context,
-                                null,
-                                logger = LongPressHandlingViewLogger(logBuffer, tag = TAG)
-                            )
-                            .apply {
-                                id = R.id.device_entry_icon_view
-                                DeviceEntryIconViewBinder.bind(
-                                    applicationScope,
-                                    this,
-                                    deviceEntryIconViewModel.get(),
-                                    deviceEntryForegroundViewModel.get(),
-                                    deviceEntryBackgroundViewModel.get(),
-                                    falsingManager.get(),
-                                    vibratorHelper.get(),
-                                    overrideColor,
-                                )
-                            }
-                    } else {
-                        // KeyguardBottomAreaRefactor.isEnabled
-                        LockIconView(context, null).apply {
-                            id = R.id.lock_icon_view
-                            lockIconViewController.get().setLockIconView(this)
-                        }
+                DeviceEntryIconView(
+                        context,
+                        null,
+                        logger = LongPressHandlingViewLogger(logBuffer, tag = TAG),
+                    )
+                    .apply {
+                        id = R.id.device_entry_icon_view
+                        DeviceEntryIconViewBinder.bind(
+                            applicationScope,
+                            this,
+                            deviceEntryIconViewModel.get(),
+                            deviceEntryForegroundViewModel.get(),
+                            deviceEntryBackgroundViewModel.get(),
+                            falsingManager.get(),
+                            vibratorHelper.get(),
+                            overrideColor,
+                        )
                     }
-                view
             },
             modifier =
                 modifier.element(LockIconElementKey).layout { measurable, _ ->
@@ -141,9 +122,7 @@
      * On devices that support UDFPS (under-display fingerprint sensor), the bounds of the icon are
      * the same as the bounds of the sensor.
      */
-    private fun lockIconBounds(
-        context: Context,
-    ): IntRect {
+    private fun lockIconBounds(context: Context): IntRect {
         val windowViewBounds = windowManager.currentWindowMetrics.bounds
         var widthPx = windowViewBounds.right.toFloat()
         if (featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) {
@@ -162,10 +141,7 @@
         val (center, radius) =
             if (authController.isUdfpsSupported && udfpsLocation != null) {
                 Pair(
-                    IntOffset(
-                        x = udfpsLocation.x,
-                        y = udfpsLocation.y,
-                    ),
+                    IntOffset(x = udfpsLocation.x, y = udfpsLocation.y),
                     authController.udfpsRadius.toInt(),
                 )
             } else {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
index 2e39524..73c4fab 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -33,7 +33,7 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
-import com.android.systemui.customization.R as customizationR
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys
 import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
 import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
@@ -57,12 +57,12 @@
         Row(
             modifier =
                 Modifier.padding(
-                        horizontal = dimensionResource(customizationR.dimen.clock_padding_start)
+                        horizontal = dimensionResource(customR.dimen.clock_padding_start)
                     )
                     .burnInAware(aodBurnInViewModel, burnInParams, isClock = true)
         ) {
             WeatherElement(
-                weatherClockElementViewId = customizationR.id.weather_clock_time,
+                weatherClockElementViewId = customR.id.weather_clock_time,
                 clock = clock,
                 elementKey = WeatherClockElementKeys.timeElementKey,
             )
@@ -75,7 +75,7 @@
         modifier: Modifier = Modifier,
     ) {
         WeatherElement(
-            weatherClockElementViewId = customizationR.id.weather_clock_date,
+            weatherClockElementViewId = customR.id.weather_clock_date,
             clock = clock,
             elementKey = WeatherClockElementKeys.dateElementKey,
             modifier = modifier,
@@ -88,7 +88,7 @@
         modifier: Modifier = Modifier,
     ) {
         WeatherElement(
-            weatherClockElementViewId = customizationR.id.weather_clock_weather_icon,
+            weatherClockElementViewId = customR.id.weather_clock_weather_icon,
             clock = clock,
             elementKey = WeatherClockElementKeys.weatherIconElementKey,
             modifier = modifier.wrapContentSize(),
@@ -101,7 +101,7 @@
         modifier: Modifier = Modifier,
     ) {
         WeatherElement(
-            weatherClockElementViewId = customizationR.id.weather_clock_alarm_dnd,
+            weatherClockElementViewId = customR.id.weather_clock_alarm_dnd,
             clock = clock,
             elementKey = WeatherClockElementKeys.dndAlarmElementKey,
             modifier = modifier.wrapContentSize(),
@@ -114,7 +114,7 @@
         modifier: Modifier = Modifier,
     ) {
         WeatherElement(
-            weatherClockElementViewId = customizationR.id.weather_clock_temperature,
+            weatherClockElementViewId = customR.id.weather_clock_temperature,
             clock = clock,
             elementKey = WeatherClockElementKeys.temperatureElementKey,
             modifier = modifier.wrapContentSize(),
@@ -159,7 +159,7 @@
             modifier =
                 Modifier.height(IntrinsicSize.Max)
                     .padding(
-                        horizontal = dimensionResource(customizationR.dimen.clock_padding_start)
+                        horizontal = dimensionResource(customR.dimen.clock_padding_start)
                     )
                     .burnInAware(aodBurnInViewModel, burnInParams, isClock = true)
         ) {
@@ -168,7 +168,7 @@
                 modifier =
                     Modifier.fillMaxSize()
                         .padding(
-                            start = dimensionResource(customizationR.dimen.clock_padding_start)
+                            start = dimensionResource(customR.dimen.clock_padding_start)
                         )
             ) {
                 Weather(clock = clock, modifier = Modifier.align(Alignment.TopStart))
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
index 8b9e927..e4c60e1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
@@ -18,6 +18,8 @@
 
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.util.fastCoerceAtLeast
+import androidx.compose.ui.util.fastCoerceAtMost
 import com.android.compose.nestedscroll.PriorityNestedScrollConnection
 
 /**
@@ -44,7 +46,7 @@
         orientation = Orientation.Vertical,
         // scrolling up and inner content is taller than the scrim, so scrim needs to
         // expand; content can scroll once scrim is at the minScrimOffset.
-        canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
+        canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ ->
             offsetAvailable < 0 &&
                 offsetBeforeStart == 0f &&
                 contentHeight() > minVisibleScrimHeight() &&
@@ -52,36 +54,38 @@
         },
         // scrolling down and content is done scrolling to top. After that, the scrim
         // needs to collapse; collapse the scrim until it is at the maxScrimOffset.
-        canStartPostScroll = { offsetAvailable, _ ->
+        canStartPostScroll = { offsetAvailable, _, _ ->
             offsetAvailable > 0 && (scrimOffset() < maxScrimOffset || isCurrentGestureOverscroll())
         },
         canStartPostFling = { false },
-        canContinueScroll = {
-            val currentHeight = scrimOffset()
-            minScrimOffset() < currentHeight && currentHeight < maxScrimOffset
-        },
-        canScrollOnFling = true,
+        canStopOnPreFling = { false },
         onStart = { offsetAvailable -> onStart(offsetAvailable) },
-        onScroll = { offsetAvailable ->
+        onScroll = { offsetAvailable, _ ->
             val currentHeight = scrimOffset()
             val amountConsumed =
                 if (offsetAvailable > 0) {
                     val amountLeft = maxScrimOffset - currentHeight
-                    offsetAvailable.coerceAtMost(amountLeft)
+                    offsetAvailable.fastCoerceAtMost(amountLeft)
                 } else {
                     val amountLeft = minScrimOffset() - currentHeight
-                    offsetAvailable.coerceAtLeast(amountLeft)
+                    offsetAvailable.fastCoerceAtLeast(amountLeft)
                 }
             snapScrimOffset(currentHeight + amountConsumed)
             amountConsumed
         },
-        // Don't consume the velocity on pre/post fling
         onStop = { velocityAvailable ->
             onStop(velocityAvailable)
             if (scrimOffset() < minScrimOffset()) {
                 animateScrimOffset(minScrimOffset())
             }
-            { 0f }
+            // Don't consume the velocity on pre/post fling
+            0f
+        },
+        onCancel = {
+            onStop(0f)
+            if (scrimOffset() < minScrimOffset()) {
+                animateScrimOffset(minScrimOffset())
+            }
         },
     )
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
index a706585..edb05eb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
@@ -28,6 +28,7 @@
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastCoerceAtLeast
 import com.android.compose.nestedscroll.PriorityNestedScrollConnection
 import kotlin.math.max
 import kotlin.math.roundToInt
@@ -86,21 +87,25 @@
 ): PriorityNestedScrollConnection {
     return PriorityNestedScrollConnection(
         orientation = Orientation.Vertical,
-        canStartPreScroll = { _, _ -> false },
-        canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
+        canStartPreScroll = { _, _, _ -> false },
+        canStartPostScroll = { offsetAvailable, offsetBeforeStart, _ ->
             offsetAvailable < 0f && offsetBeforeStart < 0f && !canScrollForward()
         },
         canStartPostFling = { velocityAvailable -> velocityAvailable < 0f && !canScrollForward() },
-        canContinueScroll = { stackOffset() > 0f },
-        canScrollOnFling = true,
+        canStopOnPreFling = { false },
         onStart = { offsetAvailable -> onStart(offsetAvailable) },
-        onScroll = { offsetAvailable ->
-            onScroll(offsetAvailable)
-            offsetAvailable
+        onScroll = { offsetAvailable, _ ->
+            val minOffset = 0f
+            val consumed = offsetAvailable.fastCoerceAtLeast(minOffset - stackOffset())
+            if (consumed != 0f) {
+                onScroll(consumed)
+            }
+            consumed
         },
         onStop = { velocityAvailable ->
             onStop(velocityAvailable)
-            suspend { velocityAvailable }
+            velocityAvailable
         },
+        onCancel = { onStop(0f) },
     )
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 54497f6..2a91bd8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -133,7 +133,14 @@
     Column(
         verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding),
         horizontalAlignment = Alignment.CenterHorizontally,
-        modifier = modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
+        modifier =
+            modifier
+                .fillMaxWidth()
+                .padding(
+                    start = QuickSettingsShade.Dimensions.Padding,
+                    end = QuickSettingsShade.Dimensions.Padding,
+                    top = QuickSettingsShade.Dimensions.Padding,
+                ),
     ) {
         BrightnessSliderContainer(
             viewModel = viewModel.brightnessSliderViewModel,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 085157a..9f99c37 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -27,9 +27,10 @@
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
 import com.android.compose.nestedscroll.PriorityNestedScrollConnection
-import com.android.compose.nestedscroll.SuspendedValue
 import kotlin.math.absoluteValue
 
+internal typealias SuspendedValue<T> = suspend () -> T
+
 internal interface DraggableHandler {
     /**
      * Start a drag in the given [startedPosition], with the given [overSlop] and number of
@@ -612,7 +613,7 @@
 
         return PriorityNestedScrollConnection(
             orientation = orientation,
-            canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
+            canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ ->
                 canChangeScene =
                     if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
 
@@ -630,7 +631,13 @@
                     return@PriorityNestedScrollConnection false
                 }
 
-                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection false
+                }
+                _lastPointersInfo = pointersInfo
 
                 // If the current swipe transition is *not* closed to 0f or 1f, then we want the
                 // scroll events to intercept the current transition to continue the scene
@@ -638,7 +645,7 @@
                 isIntercepting = true
                 true
             },
-            canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
+            canStartPostScroll = { offsetAvailable, offsetBeforeStart, _ ->
                 val behavior: NestedScrollBehavior =
                     when {
                         offsetAvailable > 0f -> topOrLeftBehavior
@@ -649,7 +656,12 @@
                 val isZeroOffset =
                     if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
 
-                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection false
+                }
+                _lastPointersInfo = pointersInfo
 
                 val canStart =
                     when (behavior) {
@@ -684,7 +696,12 @@
                 // We could start an overscroll animation
                 canChangeScene = false
 
-                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection false
+                }
+                _lastPointersInfo = pointersInfo
 
                 val canStart = behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
                 if (canStart) {
@@ -693,8 +710,7 @@
 
                 canStart
             },
-            canContinueScroll = { true },
-            canScrollOnFling = false,
+            canStopOnPreFling = { true },
             onStart = { offsetAvailable ->
                 val pointersInfo = pointersInfo()
                 dragController =
@@ -704,19 +720,33 @@
                         overSlop = if (isIntercepting) 0f else offsetAvailable,
                     )
             },
-            onScroll = { offsetAvailable ->
+            onScroll = { offsetAvailable, _ ->
                 val controller = dragController ?: error("Should be called after onStart")
 
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection 0f
+                }
+
                 // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
                 // initiated in a nested child.
                 controller.onDrag(delta = offsetAvailable)
             },
             onStop = { velocityAvailable ->
                 val controller = dragController ?: error("Should be called after onStart")
-
-                controller
-                    .onStop(velocity = velocityAvailable, canChangeContent = canChangeScene)
-                    .also { dragController = null }
+                try {
+                    controller
+                        .onStop(velocity = velocityAvailable, canChangeContent = canChangeScene)
+                        .invoke()
+                } finally {
+                    dragController = null
+                }
+            },
+            onCancel = {
+                val controller = dragController ?: error("Should be called after onStart")
+                controller.onStop(velocity = 0f, canChangeContent = canChangeScene)
+                dragController = null
             },
         )
     }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index aa70a0c..8613f6d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -29,6 +29,7 @@
 import androidx.compose.ui.input.pointer.AwaitPointerEventScope
 import androidx.compose.ui.input.pointer.PointerEvent
 import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.PointerEventType
 import androidx.compose.ui.input.pointer.PointerId
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.PointerInputScope
@@ -184,6 +185,7 @@
 
     private var startedPosition: Offset? = null
     private var pointersDown: Int = 0
+    private var isMouseWheel: Boolean = false
 
     internal fun pointersInfo(): PointersInfo {
         return PointersInfo(
@@ -191,6 +193,7 @@
             startedPosition = startedPosition,
             // We could have 0 pointers during fling or for other reasons.
             pointersDown = pointersDown.coerceAtLeast(1),
+            isMouseWheel = isMouseWheel,
         )
     }
 
@@ -202,8 +205,15 @@
             // [requireAncestorPointersInfoOwner], to our descendants.
             while (currentContext.isActive) {
                 // During the Initial pass, we receive the event after our ancestors.
-                val changes = awaitPointerEvent(PointerEventPass.Initial).changes
+                val pointerEvent = awaitPointerEvent(PointerEventPass.Initial)
+
+                // Ignore cursor has entered the input region.
+                // This will only be sent after the cursor is hovering when in the input region.
+                if (pointerEvent.type == PointerEventType.Enter) continue
+
+                val changes = pointerEvent.changes
                 pointersDown = changes.countDown()
+                isMouseWheel = pointerEvent.type == PointerEventType.Scroll
 
                 when {
                     // There are no more pointers down.
@@ -223,7 +233,8 @@
 
                     // The first pointer down, startedPosition was not set.
                     startedPosition == null -> {
-                        val firstPointerDown = changes.single()
+                        // Mouse wheel could start with multiple pointer down
+                        val firstPointerDown = changes.first()
                         velocityPointerId = firstPointerDown.id
                         velocityTracker.resetTracking()
                         velocityTracker.addPointerInputChange(firstPointerDown)
@@ -647,4 +658,8 @@
     fun pointersInfo(): PointersInfo
 }
 
-internal data class PointersInfo(val startedPosition: Offset?, val pointersDown: Int)
+internal data class PointersInfo(
+    val startedPosition: Offset?,
+    val pointersDown: Int,
+    val isMouseWheel: Boolean,
+)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 2657d7c..3c3c612 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -430,6 +430,10 @@
                     // Replace the transition.
                     transitionStates =
                         transitionStates.subList(0, transitionStates.lastIndex) + transition
+
+                    // Make sure it is removed from the finishedTransitions set if it was already
+                    // finished.
+                    finishedTransitions.remove(currentState)
                 } else {
                     // Append the new transition.
                     transitionStates = transitionStates + transition
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index 205267d..f0043e1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -27,7 +27,6 @@
 import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
-import com.android.compose.nestedscroll.SuspendedValue
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.CompletableDeferred
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
index 4ae3235..ecf64b7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
@@ -18,6 +18,8 @@
 
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.util.fastCoerceAtLeast
+import androidx.compose.ui.util.fastCoerceAtMost
 
 /**
  * A [NestedScrollConnection] that listens for all vertical scroll events and responds in the
@@ -43,35 +45,32 @@
         orientation = Orientation.Vertical,
         // When swiping up, the LargeTopAppBar will shrink (to [minHeight]) and the content will
         // expand. Then, you can then scroll down the content.
-        canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
+        canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ ->
             offsetAvailable < 0 && offsetBeforeStart == 0f && height() > minHeight()
         },
         // When swiping down, the content will scroll up until it reaches the top. Then, the
         // LargeTopAppBar will expand until it reaches its [maxHeight].
-        canStartPostScroll = { offsetAvailable, _ ->
+        canStartPostScroll = { offsetAvailable, _, _ ->
             offsetAvailable > 0 && height() < maxHeight()
         },
         canStartPostFling = { false },
-        canContinueScroll = {
-            val currentHeight = height()
-            minHeight() < currentHeight && currentHeight < maxHeight()
-        },
-        canScrollOnFling = true,
+        canStopOnPreFling = { false },
         onStart = { /* do nothing */ },
-        onScroll = { offsetAvailable ->
+        onScroll = { offsetAvailable, _ ->
             val currentHeight = height()
             val amountConsumed =
                 if (offsetAvailable > 0) {
                     val amountLeft = maxHeight() - currentHeight
-                    offsetAvailable.coerceAtMost(amountLeft)
+                    offsetAvailable.fastCoerceAtMost(amountLeft)
                 } else {
                     val amountLeft = minHeight() - currentHeight
-                    offsetAvailable.coerceAtLeast(amountLeft)
+                    offsetAvailable.fastCoerceAtLeast(amountLeft)
                 }
             onHeightChanged(currentHeight + amountConsumed)
             amountConsumed
         },
         // Don't consume the velocity on pre/post fling
-        onStop = { { 0f } },
+        onStop = { 0f },
+        onCancel = { /* do nothing */ },
     )
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index a3641e6..636c557 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -16,37 +16,59 @@
 
 package com.android.compose.nestedscroll
 
+import androidx.compose.animation.core.AnimationState
+import androidx.compose.animation.core.DecayAnimationSpec
+import androidx.compose.animation.core.animateDecay
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.unit.Velocity
 import com.android.compose.ui.util.SpaceVectorConverter
+import kotlin.math.abs
 import kotlin.math.sign
-
-internal typealias SuspendedValue<T> = suspend () -> T
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
 
 /**
- * This [NestedScrollConnection] waits for a child to scroll ([onPreScroll] or [onPostScroll]), and
- * then decides (via [canStartPreScroll] or [canStartPostScroll]) if it should take over scrolling.
- * If it does, it will scroll before its children, until [canContinueScroll] allows it.
+ * A [NestedScrollConnection] that intercepts scroll events in priority mode.
  *
- * Note: Call [reset] before destroying this object to make sure you always get a call to [onStop]
- * after [onStart].
+ * Priority mode allows this connection to take control over scroll events within a nested scroll
+ * hierarchy. When in priority mode, this connection consumes scroll events before its children,
+ * enabling custom scrolling behaviors like sticky headers.
  *
+ * @param orientation The orientation of the scroll.
+ * @param canStartPreScroll lambda that returns true if the connection can start consuming scroll
+ *   events in pre-scroll mode.
+ * @param canStartPostScroll lambda that returns true if the connection can start consuming scroll
+ *   events in post-scroll mode.
+ * @param canStartPostFling lambda that returns true if the connection can start consuming scroll
+ *   events in post-fling mode.
+ * @param canStopOnPreFling lambda that returns true if the connection can stop consuming scroll
+ *   events in pre-fling (i.e. as soon as the user lifts their fingers).
+ * @param onStart lambda that is called when the connection starts consuming scroll events.
+ * @param onScroll lambda that is called when the connection consumes a scroll event and returns the
+ *   consumed amount.
+ * @param onStop lambda that is called when the connection stops consuming scroll events and returns
+ *   the consumed velocity.
+ * @param onCancel lambda that is called when the connection is cancelled.
  * @sample LargeTopAppBarNestedScrollConnection
  * @sample com.android.compose.animation.scene.NestedScrollHandlerImpl.nestedScrollConnection
  */
 class PriorityNestedScrollConnection(
     orientation: Orientation,
-    private val canStartPreScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
-    private val canStartPostScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
+    private val canStartPreScroll:
+        (offsetAvailable: Float, offsetBeforeStart: Float, source: NestedScrollSource) -> Boolean,
+    private val canStartPostScroll:
+        (offsetAvailable: Float, offsetBeforeStart: Float, source: NestedScrollSource) -> Boolean,
     private val canStartPostFling: (velocityAvailable: Float) -> Boolean,
-    private val canContinueScroll: (source: NestedScrollSource) -> Boolean,
-    private val canScrollOnFling: Boolean,
+    private val canStopOnPreFling: () -> Boolean,
     private val onStart: (offsetAvailable: Float) -> Unit,
-    private val onScroll: (offsetAvailable: Float) -> Float,
-    private val onStop: (velocityAvailable: Float) -> SuspendedValue<Float>,
+    private val onScroll: (offsetAvailable: Float, source: NestedScrollSource) -> Float,
+    private val onStop: suspend (velocityAvailable: Float) -> Float,
+    private val onCancel: () -> Unit,
 ) : NestedScrollConnection, SpaceVectorConverter by SpaceVectorConverter(orientation) {
 
     /** In priority mode [onPreScroll] events are first consumed by the parent, via [onScroll]. */
@@ -54,6 +76,9 @@
 
     private var offsetScrolledBeforePriorityMode = 0f
 
+    /** This job allows us to interrupt the onStop animation */
+    private var onStopJob: Deferred<Float> = CompletableDeferred(0f)
+
     override fun onPostScroll(
         consumed: Offset,
         available: Offset,
@@ -64,62 +89,48 @@
         // the beginning or from the last fling gesture.
         val offsetBeforeStart = offsetScrolledBeforePriorityMode - availableFloat
 
-        if (
-            isPriorityMode ||
-                (source == NestedScrollSource.SideEffect && !canScrollOnFling) ||
-                !canStartPostScroll(availableFloat, offsetBeforeStart)
-        ) {
+        if (isPriorityMode || !canStartPostScroll(availableFloat, offsetBeforeStart, source)) {
             // The priority mode cannot start so we won't consume the available offset.
             return Offset.Zero
         }
 
-        return onPriorityStart(availableFloat).toOffset()
+        return start(availableFloat, source).toOffset()
     }
 
     override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
         if (!isPriorityMode) {
-            if (source == NestedScrollSource.UserInput || canScrollOnFling) {
-                val availableFloat = available.toFloat()
-                if (canStartPreScroll(availableFloat, offsetScrolledBeforePriorityMode)) {
-                    return onPriorityStart(availableFloat).toOffset()
-                }
-                // We want to track the amount of offset consumed before entering priority mode
-                offsetScrolledBeforePriorityMode += availableFloat
+            val availableFloat = available.toFloat()
+            if (canStartPreScroll(availableFloat, offsetScrolledBeforePriorityMode, source)) {
+                return start(availableFloat, source).toOffset()
             }
-
-            return Offset.Zero
-        }
-
-        val availableFloat = available.toFloat()
-        if (!canContinueScroll(source)) {
-            // Step 3a: We have lost priority and we no longer need to intercept scroll events.
-            onPriorityStop(velocity = 0f)
-
-            // We've just reset offsetScrolledBeforePriorityMode to 0f
             // We want to track the amount of offset consumed before entering priority mode
             offsetScrolledBeforePriorityMode += availableFloat
-
             return Offset.Zero
         }
 
-        // Step 2: We have the priority and can consume the scroll events.
-        return onScroll(availableFloat).toOffset()
+        return scroll(available.toFloat(), source).toOffset()
     }
 
     override suspend fun onPreFling(available: Velocity): Velocity {
-        if (isPriorityMode && canScrollOnFling) {
-            // We don't want to consume the velocity, we prefer to continue receiving scroll events.
+        if (!isPriorityMode) {
+            resetOffsetTracker()
             return Velocity.Zero
         }
-        // Step 3b: The finger is lifted, we can stop intercepting scroll events and use the speed
-        // of the fling gesture.
-        return onPriorityStop(velocity = available.toFloat()).invoke().toVelocity()
+
+        if (canStopOnPreFling()) {
+            // Step 3b: The finger is lifted, we can stop intercepting scroll events and use the
+            // velocity of the fling gesture.
+            return stop(velocityAvailable = available.toFloat()).toVelocity()
+        }
+
+        // We don't want to consume the velocity, we prefer to continue receiving scroll events.
+        return Velocity.Zero
     }
 
     override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
         val availableFloat = available.toFloat()
         if (isPriorityMode) {
-            return onPriorityStop(velocity = availableFloat).invoke().toVelocity()
+            return stop(velocityAvailable = availableFloat).toVelocity()
         }
 
         if (!canStartPostFling(availableFloat)) {
@@ -131,10 +142,14 @@
         // TODO(b/291053278): Remove canStartPostFling() and instead make it possible to define the
         // overscroll behavior on the Scene level.
         val smallOffset = availableFloat.sign
-        onPriorityStart(availableOffset = smallOffset)
+        start(
+            availableOffset = smallOffset,
+            source = NestedScrollSource.SideEffect,
+            skipScroll = true,
+        )
 
         // This is the last event of a scroll gesture.
-        return onPriorityStop(availableFloat).invoke().toVelocity()
+        return stop(availableFloat).toVelocity()
     }
 
     /**
@@ -143,36 +158,76 @@
      * TODO(b/303224944) This method should be removed.
      */
     fun reset() {
-        // Step 3c: To ensure that an onStop is always called for every onStart.
-        onPriorityStop(velocity = 0f)
+        if (isPriorityMode) {
+            // Step 3c: To ensure that an onStop (or onCancel) is always called for every onStart.
+            cancel()
+        } else {
+            resetOffsetTracker()
+        }
     }
 
-    private fun onPriorityStart(availableOffset: Float): Float {
-        if (isPriorityMode) {
-            error("This should never happen, onPriorityStart() was called when isPriorityMode")
+    private fun shouldStop(consumed: Float): Boolean {
+        return consumed == 0f
+    }
+
+    private fun start(
+        availableOffset: Float,
+        source: NestedScrollSource,
+        skipScroll: Boolean = false,
+    ): Float {
+        check(!isPriorityMode) {
+            "This should never happen, start() was called when isPriorityMode"
         }
 
         // Step 1: It's our turn! We start capturing scroll events when one of our children has an
         // available offset following a scroll event.
         isPriorityMode = true
 
+        onStopJob.cancel()
+
         // Note: onStop will be called if we cannot continue to scroll (step 3a), or the finger is
         // lifted (step 3b), or this object has been destroyed (step 3c).
         onStart(availableOffset)
 
-        return onScroll(availableOffset)
+        return if (skipScroll) 0f else scroll(availableOffset, source)
     }
 
-    private fun onPriorityStop(velocity: Float): SuspendedValue<Float> {
-        // We can restart tracking the consumed offsets from scratch.
-        offsetScrolledBeforePriorityMode = 0f
+    private fun scroll(offsetAvailable: Float, source: NestedScrollSource): Float {
+        // Step 2: We have the priority and can consume the scroll events.
+        val consumedByScroll = onScroll(offsetAvailable, source)
 
-        if (!isPriorityMode) {
-            return { 0f }
+        if (shouldStop(consumedByScroll)) {
+            // Step 3a: We have lost priority and we no longer need to intercept scroll events.
+            cancel()
+
+            // We've just reset offsetScrolledBeforePriorityMode to 0f
+            // We want to track the amount of offset consumed before entering priority mode
+            offsetScrolledBeforePriorityMode += offsetAvailable - consumedByScroll
         }
 
-        isPriorityMode = false
+        return consumedByScroll
+    }
 
-        return onStop(velocity)
+    /** Reset the tracking of consumed offsets before entering in priority mode. */
+    private fun resetOffsetTracker() {
+        offsetScrolledBeforePriorityMode = 0f
+    }
+
+    private suspend fun stop(velocityAvailable: Float): Float {
+        check(isPriorityMode) { "This should never happen, stop() was called before start()" }
+        isPriorityMode = false
+        resetOffsetTracker()
+
+        return coroutineScope {
+            onStopJob = async { onStop(velocityAvailable) }
+            onStopJob.await()
+        }
+    }
+
+    private fun cancel() {
+        check(isPriorityMode) { "This should never happen, cancel() was called before start()" }
+        isPriorityMode = false
+        resetOffsetTracker()
+        onCancel()
     }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index ecef6be..a0fed90 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -39,7 +39,6 @@
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.content.state.TransitionState.Transition
 import com.android.compose.animation.scene.subjects.assertThat
-import com.android.compose.nestedscroll.SuspendedValue
 import com.android.compose.test.MonotonicClockTestScope
 import com.android.compose.test.runMonotonicClockTest
 import com.android.compose.test.transition
@@ -128,7 +127,7 @@
         val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)
 
         var pointerInfoOwner: () -> PointersInfo = {
-            PointersInfo(startedPosition = Offset.Zero, pointersDown = 1)
+            PointersInfo(startedPosition = Offset.Zero, pointersDown = 1, isMouseWheel = false)
         }
 
         fun nestedScrollConnection(
@@ -1188,7 +1187,9 @@
         val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
 
         // Drag from the **top** of the screen
-        pointerInfoOwner = { PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1) }
+        pointerInfoOwner = {
+            PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1, isMouseWheel = false)
+        }
         assertIdle(currentScene = SceneC)
 
         nestedScroll.scroll(available = upOffset(fractionOfScreen = 0.1f))
@@ -1206,7 +1207,11 @@
 
         // Drag from the **bottom** of the screen
         pointerInfoOwner = {
-            PointersInfo(startedPosition = Offset(0f, SCREEN_SIZE), pointersDown = 1)
+            PointersInfo(
+                startedPosition = Offset(0f, SCREEN_SIZE),
+                pointersDown = 1,
+                isMouseWheel = false,
+            )
         }
         assertIdle(currentScene = SceneC)
 
@@ -1221,6 +1226,22 @@
     }
 
     @Test
+    fun ignoreMouseWheel() = runGestureTest {
+        // Start at scene C.
+        navigateToSceneC()
+        val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
+
+        // Use mouse wheel
+        pointerInfoOwner = {
+            PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1, isMouseWheel = true)
+        }
+        assertIdle(currentScene = SceneC)
+
+        nestedScroll.scroll(available = upOffset(fractionOfScreen = 0.1f))
+        assertIdle(currentScene = SceneC)
+    }
+
+    @Test
     fun transitionIsImmediatelyUpdatedWhenReleasingFinger() = runGestureTest {
         // Swipe up from the middle to transition to scene B.
         val middle = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index c8f6e6d..3df6087 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -46,7 +46,6 @@
 import androidx.compose.ui.unit.Velocity
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.modifiers.thenIf
-import com.android.compose.nestedscroll.SuspendedValue
 import com.google.common.truth.Truth.assertThat
 import kotlin.properties.Delegates
 import kotlinx.coroutines.coroutineScope
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index f3a3488..f5bb5ba 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -727,4 +727,45 @@
         // The previous job is cancelled and does not infinitely collect the progress.
         job.join()
     }
+
+    @Test
+    fun replacedTransitionIsRemovedFromFinishedTransitions() = runTest {
+        val state = MutableSceneTransitionLayoutState(SceneA)
+
+        val aToB =
+            transition(
+                SceneA,
+                SceneB,
+                onFreezeAndAnimate = {
+                    // Do nothing, so that this transition stays in the transitionStates list and we
+                    // can finish() it manually later.
+                },
+            )
+        val replacingAToB = transition(SceneB, SceneC)
+        val replacingBToC = transition(SceneB, SceneC, replacedTransition = replacingAToB)
+
+        // Start A => B.
+        val aToBJob = state.startTransitionImmediately(animationScope = this, aToB)
+
+        // Start B => C and immediately finish it. It will be flagged as finished in
+        // STLState.finishedTransitions given that A => B is not finished yet.
+        val bToCJob = state.startTransitionImmediately(animationScope = this, replacingAToB)
+        replacingAToB.finish()
+        bToCJob.join()
+
+        // Start a new B => C that replaces the previously finished B => C.
+        val replacingBToCJob =
+            state.startTransitionImmediately(animationScope = this, replacingBToC)
+
+        // Finish A => B.
+        aToB.finish()
+        aToBJob.join()
+
+        // Finish the new B => C.
+        replacingBToC.finish()
+        replacingBToCJob.join()
+
+        assertThat(state.transitionState).isIdle()
+        assertThat(state.transitionState).hasCurrentScene(SceneC)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 28d0a47..3001505 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -17,6 +17,8 @@
 package com.android.compose.animation.scene
 
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.rememberScrollableState
+import androidx.compose.foundation.gestures.scrollable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
@@ -39,12 +41,14 @@
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ScrollWheel
 import androidx.compose.ui.test.assertPositionInRootIsEqualTo
 import androidx.compose.ui.test.assertTextEquals
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onRoot
 import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performMouseInput
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipeRight
 import androidx.compose.ui.test.swipeUp
@@ -102,26 +106,22 @@
             modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName),
         ) {
             scene(
-                SceneA,
+                key = SceneA,
                 userActions =
                     if (swipesEnabled())
-                        mapOf(
-                            Swipe.Left to SceneB,
-                            Swipe.Down to TestScenes.SceneC,
-                            Swipe.Up to SceneB,
-                        )
+                        mapOf(Swipe.Left to SceneB, Swipe.Down to SceneC, Swipe.Up to SceneB)
                     else emptyMap(),
             ) {
                 Box(Modifier.fillMaxSize())
             }
             scene(
-                SceneB,
+                key = SceneB,
                 userActions = if (swipesEnabled()) mapOf(Swipe.Right to SceneA) else emptyMap(),
             ) {
                 Box(Modifier.fillMaxSize())
             }
             scene(
-                TestScenes.SceneC,
+                key = SceneC,
                 userActions =
                     if (swipesEnabled())
                         mapOf(
@@ -196,7 +196,7 @@
         // Drag is in progress, so currentScene = SceneA and progress = 56dp / LayoutHeight
         transition = assertThat(layoutState.transitionState).isSceneTransition()
         assertThat(transition).hasFromScene(SceneA)
-        assertThat(transition).hasToScene(TestScenes.SceneC)
+        assertThat(transition).hasToScene(SceneC)
         assertThat(transition).hasCurrentScene(SceneA)
         assertThat(transition).hasProgress(56.dp / LayoutHeight)
         assertThat(transition).isInitiatedByUserInput()
@@ -206,15 +206,15 @@
         rule.onRoot().performTouchInput { up() }
         transition = assertThat(layoutState.transitionState).isSceneTransition()
         assertThat(transition).hasFromScene(SceneA)
-        assertThat(transition).hasToScene(TestScenes.SceneC)
-        assertThat(transition).hasCurrentScene(TestScenes.SceneC)
+        assertThat(transition).hasToScene(SceneC)
+        assertThat(transition).hasCurrentScene(SceneC)
         assertThat(transition).hasProgress(56.dp / LayoutHeight)
         assertThat(transition).isInitiatedByUserInput()
 
         // Wait for the animation to finish. We should now be in scene C.
         rule.waitForIdle()
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
     }
 
     @Test
@@ -271,20 +271,20 @@
         // We should be animating to C (currentScene = SceneC).
         transition = assertThat(layoutState.transitionState).isSceneTransition()
         assertThat(transition).hasFromScene(SceneA)
-        assertThat(transition).hasToScene(TestScenes.SceneC)
-        assertThat(transition).hasCurrentScene(TestScenes.SceneC)
+        assertThat(transition).hasToScene(SceneC)
+        assertThat(transition).hasCurrentScene(SceneC)
         assertThat(transition).hasProgress(55.dp / LayoutHeight)
 
         // Wait for the animation to finish. We should now be in scene C.
         rule.waitForIdle()
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
     }
 
     @Test
     fun multiPointerSwipe() {
         // Start at scene C.
-        val layoutState = layoutState(TestScenes.SceneC)
+        val layoutState = layoutState(SceneC)
 
         // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
         // detected as a drag event.
@@ -295,7 +295,7 @@
         }
 
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
 
         // Swipe down with two fingers.
         rule.onRoot().performTouchInput {
@@ -307,7 +307,7 @@
 
         // We are transitioning to B because we used 2 fingers.
         val transition = assertThat(layoutState.transitionState).isSceneTransition()
-        assertThat(transition).hasFromScene(TestScenes.SceneC)
+        assertThat(transition).hasFromScene(SceneC)
         assertThat(transition).hasToScene(SceneB)
 
         // Release the fingers and wait for the animation to end. We are back to C because we only
@@ -315,13 +315,13 @@
         rule.onRoot().performTouchInput { repeat(2) { i -> up(pointerId = i) } }
         rule.waitForIdle()
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
     }
 
     @Test
     fun defaultEdgeSwipe() {
         // Start at scene C.
-        val layoutState = layoutState(TestScenes.SceneC)
+        val layoutState = layoutState(SceneC)
 
         // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
         // detected as a drag event.
@@ -332,7 +332,7 @@
         }
 
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
 
         // Swipe down from the top edge.
         rule.onRoot().performTouchInput {
@@ -342,7 +342,7 @@
 
         // We are transitioning to B (and not A) because we started from the top edge.
         var transition = assertThat(layoutState.transitionState).isSceneTransition()
-        assertThat(transition).hasFromScene(TestScenes.SceneC)
+        assertThat(transition).hasFromScene(SceneC)
         assertThat(transition).hasToScene(SceneB)
 
         // Release the fingers and wait for the animation to end. We are back to C because we only
@@ -350,7 +350,7 @@
         rule.onRoot().performTouchInput { up() }
         rule.waitForIdle()
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
 
         // Swipe right from the left edge.
         rule.onRoot().performTouchInput {
@@ -360,7 +360,7 @@
 
         // We are transitioning to B (and not A) because we started from the left edge.
         transition = assertThat(layoutState.transitionState).isSceneTransition()
-        assertThat(transition).hasFromScene(TestScenes.SceneC)
+        assertThat(transition).hasFromScene(SceneC)
         assertThat(transition).hasToScene(SceneB)
 
         // Release the fingers and wait for the animation to end. We are back to C because we only
@@ -368,7 +368,7 @@
         rule.onRoot().performTouchInput { up() }
         rule.waitForIdle()
         assertThat(layoutState.transitionState).isIdle()
-        assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
+        assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
     }
 
     @Test
@@ -434,7 +434,7 @@
 
         // We should still correctly compute that we are swiping down to scene C.
         var transition = assertThat(layoutState.transitionState).isSceneTransition()
-        assertThat(transition).hasToScene(TestScenes.SceneC)
+        assertThat(transition).hasToScene(SceneC)
 
         // Release the finger, animating back to scene A.
         rule.onRoot().performTouchInput { up() }
@@ -502,6 +502,89 @@
     }
 
     @Test
+    fun mouseWheel_pointerInputApi_ignoredByStl() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            TestContent(layoutState)
+        }
+
+        rule.onRoot().performMouseInput {
+            enter(middle)
+            scroll(touchSlop, ScrollWheel.Vertical)
+        }
+
+        // Mouse wheel scroll are ignored
+        assertThat(layoutState.currentTransition).isNull()
+    }
+
+    @Test
+    fun mouseWheel_scrollableCannotScroll_ignoredByStl() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(layoutState, Modifier.size(LayoutWidth, LayoutHeight)) {
+                scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) {
+                    Box(
+                        Modifier.fillMaxSize()
+                            // A scrollable that does not consume the scroll gesture
+                            .scrollable(rememberScrollableState { 0f }, Orientation.Vertical)
+                    )
+                }
+                scene(SceneB) { Box(Modifier.fillMaxSize()) }
+            }
+        }
+
+        rule.onRoot().performMouseInput {
+            enter(middle)
+            scroll(touchSlop, ScrollWheel.Vertical)
+        }
+
+        // Mouse wheel scroll are ignored
+        assertThat(layoutState.currentTransition).isNull()
+    }
+
+    @Test
+    fun mouseWheel_scrollableConsume_ignoredByStl() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        var lastScroll = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(layoutState, Modifier.size(LayoutWidth, LayoutHeight)) {
+                scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) {
+                    Box(
+                        Modifier.fillMaxSize()
+                            // A scrollable that consumes the scroll gesture
+                            .scrollable(
+                                rememberScrollableState {
+                                    lastScroll = it
+                                    it
+                                },
+                                Orientation.Vertical,
+                            )
+                    )
+                }
+                scene(SceneB) { Box(Modifier.fillMaxSize()) }
+            }
+        }
+
+        rule.onRoot().performMouseInput {
+            enter(middle)
+            scroll(touchSlop * 10, ScrollWheel.Vertical)
+        }
+
+        // Mouse wheel scroll are ignored
+        assertThat(layoutState.currentTransition).isNull()
+
+        // Mouse wheel scroll can still be consumed by the scrollable
+        assertThat(lastScroll).isNotEqualTo(0f)
+        assertThat(touchSlop).isNotEqualTo(0f)
+    }
+
+    @Test
     fun transitionKey() {
         val transitionkey = TransitionKey(debugName = "foo")
         val state =
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index badc43b..1a3b86b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -34,30 +34,31 @@
     private var canStartPreScroll = false
     private var canStartPostScroll = false
     private var canStartPostFling = false
-    private var canContinueScroll = false
+    private var canStopOnPreFling = true
     private var isStarted = false
     private var lastScroll: Float? = null
-    private var returnOnScroll = 0f
+    private var consumeScroll = true
     private var lastStop: Float? = null
-    private var returnOnStop = 0f
+    private var isCancelled: Boolean = false
+    private var consumeStop = true
 
     private val scrollConnection =
         PriorityNestedScrollConnection(
             orientation = Orientation.Vertical,
-            canStartPreScroll = { _, _ -> canStartPreScroll },
-            canStartPostScroll = { _, _ -> canStartPostScroll },
+            canStartPreScroll = { _, _, _ -> canStartPreScroll },
+            canStartPostScroll = { _, _, _ -> canStartPostScroll },
             canStartPostFling = { canStartPostFling },
-            canContinueScroll = { canContinueScroll },
-            canScrollOnFling = false,
+            canStopOnPreFling = { canStopOnPreFling },
             onStart = { isStarted = true },
-            onScroll = {
-                lastScroll = it
-                returnOnScroll
+            onScroll = { offsetAvailable, _ ->
+                lastScroll = offsetAvailable
+                if (consumeScroll) offsetAvailable else 0f
             },
             onStop = {
                 lastStop = it
-                { returnOnStop }
+                if (consumeStop) it else 0f
             },
+            onCancel = { isCancelled = true },
         )
 
     @Test
@@ -85,7 +86,7 @@
         canStartPostScroll = true
         scrollConnection.onPostScroll(
             consumed = Offset.Zero,
-            available = Offset.Zero,
+            available = Offset(1f, 1f),
             source = UserInput,
         )
     }
@@ -136,45 +137,55 @@
     @Test
     fun step2_onPriorityMode_shouldContinueIfAllowed() {
         startPriorityModePostScroll()
-        canContinueScroll = true
 
-        scrollConnection.onPreScroll(available = Offset(1f, 1f), source = UserInput)
+        val scroll1 = scrollConnection.onPreScroll(available = Offset(0f, 1f), source = UserInput)
         assertThat(lastScroll).isEqualTo(1f)
+        assertThat(scroll1.y).isEqualTo(1f)
 
-        canContinueScroll = false
-        scrollConnection.onPreScroll(available = Offset(2f, 2f), source = UserInput)
-        assertThat(lastScroll).isNotEqualTo(2f)
-        assertThat(lastScroll).isEqualTo(1f)
+        consumeScroll = false
+        val scroll2 = scrollConnection.onPreScroll(available = Offset(0f, 2f), source = UserInput)
+        assertThat(lastScroll).isEqualTo(2f)
+        assertThat(scroll2.y).isEqualTo(0f)
     }
 
     @Test
-    fun step3a_onPriorityMode_shouldStopIfCannotContinue() {
+    fun step3a_onPriorityMode_shouldCancelIfCannotContinue() {
         startPriorityModePostScroll()
-        canContinueScroll = false
+        consumeScroll = false
 
-        scrollConnection.onPreScroll(available = Offset.Zero, source = UserInput)
+        scrollConnection.onPreScroll(available = Offset(0f, 1f), source = UserInput)
 
-        assertThat(lastStop).isNotNull()
+        assertThat(isCancelled).isTrue()
     }
 
     @Test
     fun step3b_onPriorityMode_shouldStopOnFling() = runTest {
         startPriorityModePostScroll()
-        canContinueScroll = true
 
         scrollConnection.onPreFling(available = Velocity.Zero)
 
-        assertThat(lastStop).isNotNull()
+        assertThat(lastStop).isEqualTo(0f)
     }
 
     @Test
-    fun step3c_onPriorityMode_shouldStopOnReset() {
+    fun ifCannotStopOnPreFling_shouldStopOnPostFling() = runTest {
         startPriorityModePostScroll()
-        canContinueScroll = true
+        canStopOnPreFling = false
+
+        scrollConnection.onPreFling(available = Velocity.Zero)
+        assertThat(lastStop).isNull()
+
+        scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
+        assertThat(lastStop).isEqualTo(0f)
+    }
+
+    @Test
+    fun step3c_onPriorityMode_shouldCancelOnReset() {
+        startPriorityModePostScroll()
 
         scrollConnection.reset()
 
-        assertThat(lastStop).isNotNull()
+        assertThat(isCancelled).isTrue()
     }
 
     @Test
diff --git a/packages/SystemUI/customization/res/values/ids.xml b/packages/SystemUI/customization/res/values/ids.xml
index ec466f0..3a3e06b 100644
--- a/packages/SystemUI/customization/res/values/ids.xml
+++ b/packages/SystemUI/customization/res/values/ids.xml
@@ -1,5 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
+    <item type="id" name="lockscreen_clock_view_large" />
+    <item type="id" name="lockscreen_clock_view" />
+
     <!-- View ids for elements in large weather clock -->
     <item type="id" name="weather_clock_time" />
     <item type="id" name="weather_clock_date" />
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
index 9b94c91..eedddb2 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -30,16 +30,16 @@
 import com.android.systemui.plugins.clocks.ClockReactiveSetting
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.clocks.ZenData
-import com.android.systemui.shared.clocks.view.DigitalClockFaceView
 import com.android.systemui.shared.clocks.view.FlexClockView
+import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
 import java.util.Locale
 import java.util.TimeZone
 
 class ComposedDigitalLayerController(
     private val ctx: Context,
-    private val assets: AssetLoader,
+    private val resources: Resources,
+    private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
     private val layer: ComposedDigitalHandLayer,
-    private val isLargeClock: Boolean,
     messageBuffer: MessageBuffer,
 ) : SimpleClockLayerController {
     private val logger = Logger(messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
@@ -48,34 +48,22 @@
     val dozeState = DefaultClockController.AnimationState(1F)
     var isRegionDark = true
 
-    override var view: DigitalClockFaceView =
-        when (layer.customizedView) {
-            "FlexClockView" -> FlexClockView(ctx, assets, messageBuffer)
-            else -> {
-                throw IllegalStateException("CustomizedView string is not valid")
-            }
-        }
-
-    // Matches LayerControllerConstructor
-    internal constructor(
-        ctx: Context,
-        assets: AssetLoader,
-        layer: ClockLayer,
-        isLargeClock: Boolean,
-        messageBuffer: MessageBuffer,
-    ) : this(ctx, assets, layer as ComposedDigitalHandLayer, isLargeClock, messageBuffer)
+    override val view = FlexClockView(ctx, assets, messageBuffer)
 
     init {
         layer.digitalLayers.forEach {
+            val childView = SimpleDigitalClockTextView(ctx, messageBuffer)
             val controller =
-                SimpleClockLayerController.Factory.create(
+                SimpleDigitalHandLayerController(
                     ctx,
+                    resources,
                     assets,
-                    it,
-                    isLargeClock,
+                    it as DigitalHandLayer,
+                    childView,
                     messageBuffer,
                 )
-            view.addView(controller.view)
+
+            view.addView(childView)
             layerControllers.add(controller)
         }
     }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index ac26842..3903dba 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -53,11 +53,8 @@
         }
 
         return if (clockReactiveVariants) {
-            // TODO handle the case here where only the smallClock message buffer is added
-            val assetLoader =
-                AssetLoader(ctx, ctx, "clocks/", messageBuffers?.smallClockMessageBuffer!!)
-
-            SimpleClockController(ctx, assetLoader, FLEX_DESIGN, messageBuffers)
+            val assets = AssetLoader(ctx, ctx, "clocks/", messageBuffers!!.infraMessageBuffer)
+            FlexClockController(ctx, resources, assets, FLEX_DESIGN, messageBuffers)
         } else {
             DefaultClockController(
                 ctx,
@@ -82,6 +79,9 @@
             resources.getString(R.string.clock_default_description),
             // TODO(b/352049256): Update placeholder to actual resource
             resources.getDrawable(R.drawable.clock_default_thumbnail, null),
+            isReactiveToTone = true,
+            isReactiveToTouch = clockReactiveVariants,
+            axes = listOf(), // TODO: Ater some picker definition
         )
     }
 
@@ -118,9 +118,9 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER
+                                            VerticalAlignment.CENTER,
                                         ),
-                                    dateTimeFormat = "hh"
+                                    dateTimeFormat = "hh",
                                 ),
                                 DigitalHandLayer(
                                     layerBounds = LayerBounds.FIT,
@@ -146,9 +146,9 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER
+                                            VerticalAlignment.CENTER,
                                         ),
-                                    dateTimeFormat = "hh"
+                                    dateTimeFormat = "hh",
                                 ),
                                 DigitalHandLayer(
                                     layerBounds = LayerBounds.FIT,
@@ -174,9 +174,9 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER
+                                            VerticalAlignment.CENTER,
                                         ),
-                                    dateTimeFormat = "mm"
+                                    dateTimeFormat = "mm",
                                 ),
                                 DigitalHandLayer(
                                     layerBounds = LayerBounds.FIT,
@@ -202,11 +202,11 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER
+                                            VerticalAlignment.CENTER,
                                         ),
-                                    dateTimeFormat = "mm"
-                                )
-                            )
+                                    dateTimeFormat = "mm",
+                                ),
+                            ),
                     )
                 )
 
@@ -230,7 +230,7 @@
                                 renderType = RenderType.CHANGE_WEIGHT,
                             ),
                         alignment = DigitalAlignment(HorizontalAlignment.LEFT, null),
-                        dateTimeFormat = "h:mm"
+                        dateTimeFormat = "h:mm",
                     )
                 )
 
@@ -239,7 +239,7 @@
                 name = "@string/clock_default_name",
                 description = "@string/clock_default_description",
                 large = ClockFace(layers = largeLayer),
-                small = ClockFace(layers = smallLayer)
+                small = ClockFace(layers = smallLayer),
             )
         }
     }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
similarity index 82%
rename from packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockController.kt
rename to packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index ec77798..b8ebd0f 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -18,7 +18,7 @@
 
 import android.content.Context
 import android.content.res.Resources
-import com.android.systemui.monet.Style as MonetStyle
+import com.android.systemui.customization.R
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
@@ -27,21 +27,24 @@
 import com.android.systemui.plugins.clocks.ClockReactiveSetting
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.view.FlexClockView
 import java.io.PrintWriter
 import java.util.Locale
 import java.util.TimeZone
 
-/** Controller for a simple json specified clock */
-class SimpleClockController(
+/** Controller for the default flex clock */
+class FlexClockController(
     private val ctx: Context,
-    private val assets: AssetLoader,
-    val design: ClockDesign,
+    private val resources: Resources,
+    private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+    val design: ClockDesign, // TODO(b/364680879): Remove when done inlining
     val messageBuffers: ClockMessageBuffers?,
 ) : ClockController {
     override val smallClock = run {
         val buffer = messageBuffers?.smallClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
-        SimpleClockFaceController(
+        FlexClockFaceController(
             ctx,
+            resources,
             assets.copy(messageBuffer = buffer),
             design.small ?: design.large!!,
             false,
@@ -51,8 +54,9 @@
 
     override val largeClock = run {
         val buffer = messageBuffers?.largeClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
-        SimpleClockFaceController(
+        FlexClockFaceController(
             ctx,
+            resources,
             assets.copy(messageBuffer = buffer),
             design.large ?: design.small!!,
             true,
@@ -62,16 +66,10 @@
 
     override val config: ClockConfig by lazy {
         ClockConfig(
-            design.id,
-            design.name?.let { assets.tryReadString(it) ?: it } ?: "",
-            design.description?.let { assets.tryReadString(it) ?: it } ?: "",
-            isReactiveToTone =
-                design.colorPalette == null || design.colorPalette == MonetStyle.CLOCK,
-            useAlternateSmartspaceAODTransition =
-                smallClock.config.hasCustomWeatherDataDisplay ||
-                    largeClock.config.hasCustomWeatherDataDisplay,
-            useCustomClockScene =
-                smallClock.config.useCustomClockScene || largeClock.config.useCustomClockScene,
+            DEFAULT_CLOCK_ID,
+            resources.getString(R.string.clock_default_name),
+            resources.getString(R.string.clock_default_description),
+            isReactiveToTone = true,
         )
     }
 
@@ -80,8 +78,8 @@
             override var isReactiveTouchInteractionEnabled = false
                 set(value) {
                     field = value
-                    smallClock.events.isReactiveTouchInteractionEnabled = value
-                    largeClock.events.isReactiveTouchInteractionEnabled = value
+                    val view = largeClock.view as FlexClockView
+                    view.isReactiveTouchInteractionEnabled = value
                 }
 
             override fun onTimeZoneChanged(timeZone: TimeZone) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
new file mode 100644
index 0000000..ef24d2a
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.clocks
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.widget.FrameLayout
+import com.android.systemui.customization.R
+import com.android.systemui.log.core.MessageBuffer
+import com.android.systemui.plugins.clocks.AlarmData
+import com.android.systemui.plugins.clocks.ClockAnimations
+import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockFaceConfig
+import com.android.systemui.plugins.clocks.ClockFaceController
+import com.android.systemui.plugins.clocks.ClockFaceEvents
+import com.android.systemui.plugins.clocks.ClockFaceLayout
+import com.android.systemui.plugins.clocks.ClockReactiveSetting
+import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
+import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.view.FlexClockView
+import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
+import java.util.Locale
+import java.util.TimeZone
+import kotlin.math.max
+
+// TODO(b/364680879): Merge w/ ComposedDigitalLayerController
+class FlexClockFaceController(
+    ctx: Context,
+    private val resources: Resources,
+    val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+    face: ClockFace,
+    private val isLargeClock: Boolean,
+    messageBuffer: MessageBuffer,
+) : ClockFaceController {
+    override val view: View
+        get() = layerController.view
+
+    override val config =
+        ClockFaceConfig(
+            hasCustomPositionUpdatedAnimation = false // TODO(b/364673982)
+        )
+
+    private val keyguardLargeClockTopMargin =
+        resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
+    val layerController: SimpleClockLayerController
+    val timespecHandler = DigitalTimespecHandler(DigitalTimespec.TIME_FULL_FORMAT, "hh:mm")
+
+    init {
+        val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+        lp.gravity = Gravity.CENTER
+
+        val layer = face.layers[0]
+
+        layerController =
+            if (isLargeClock)
+                ComposedDigitalLayerController(
+                    ctx,
+                    resources,
+                    assets,
+                    layer as ComposedDigitalHandLayer,
+                    messageBuffer,
+                )
+            else {
+                val childView = SimpleDigitalClockTextView(ctx, messageBuffer)
+                SimpleDigitalHandLayerController(
+                    ctx,
+                    resources,
+                    assets,
+                    layer as DigitalHandLayer,
+                    childView,
+                    messageBuffer,
+                )
+            }
+        layerController.view.layoutParams = lp
+    }
+
+    override val layout: ClockFaceLayout =
+        DefaultClockFaceLayout(view).apply {
+            views[0].id =
+                if (isLargeClock) R.id.lockscreen_clock_view_large else R.id.lockscreen_clock_view
+        }
+
+    override val events = FlexClockFaceEvents()
+
+    // TODO(b/364680879): Remove ClockEvents
+    inner class FlexClockFaceEvents : ClockEvents, ClockFaceEvents {
+        override var isReactiveTouchInteractionEnabled = false
+            get() = field
+            set(value) {
+                field = value
+                layerController.events.isReactiveTouchInteractionEnabled = value
+            }
+
+        override fun onTimeTick() {
+            timespecHandler.updateTime()
+            view.contentDescription = timespecHandler.getContentDescription()
+            layerController.faceEvents.onTimeTick()
+        }
+
+        override fun onTimeZoneChanged(timeZone: TimeZone) {
+            timespecHandler.timeZone = timeZone
+            layerController.events.onTimeZoneChanged(timeZone)
+        }
+
+        override fun onTimeFormatChanged(is24Hr: Boolean) {
+            timespecHandler.is24Hr = is24Hr
+            layerController.events.onTimeFormatChanged(is24Hr)
+        }
+
+        override fun onLocaleChanged(locale: Locale) {
+            timespecHandler.updateLocale(locale)
+            layerController.events.onLocaleChanged(locale)
+        }
+
+        override fun onFontSettingChanged(fontSizePx: Float) {
+            layerController.faceEvents.onFontSettingChanged(fontSizePx)
+        }
+
+        override fun onColorPaletteChanged(resources: Resources) {
+            layerController.events.onColorPaletteChanged(resources)
+            layerController.updateColors()
+        }
+
+        override fun onSeedColorChanged(seedColor: Int?) {
+            layerController.events.onSeedColorChanged(seedColor)
+            layerController.updateColors()
+        }
+
+        override fun onRegionDarknessChanged(isRegionDark: Boolean) {
+            layerController.faceEvents.onRegionDarknessChanged(isRegionDark)
+        }
+
+        override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {}
+
+        /**
+         * targetRegion passed to all customized clock applies counter translationY of
+         * KeyguardStatusView and keyguard_large_clock_top_margin from default clock
+         */
+        override fun onTargetRegionChanged(targetRegion: Rect?) {
+            // When a clock needs to be aligned with screen, like weather clock
+            // it needs to offset back the translation of keyguard_large_clock_top_margin
+            if (isLargeClock && (view as FlexClockView).isAlignedWithScreen()) {
+                val topMargin = keyguardLargeClockTopMargin
+                targetRegion?.let {
+                    val (_, yDiff) = computeLayoutDiff(view, it, isLargeClock)
+                    // In LS, we use yDiff to counter translate
+                    // the translation of KeyguardLargeClockTopMargin
+                    // With the targetRegion passed from picker,
+                    // we will have yDiff = 0, no translation is needed for weather clock
+                    if (yDiff.toInt() != 0) view.translationY = yDiff - topMargin / 2
+                }
+                return
+            }
+
+            var maxWidth = 0f
+            var maxHeight = 0f
+
+            layerController.faceEvents.onTargetRegionChanged(targetRegion)
+            maxWidth = max(maxWidth, view.layoutParams.width.toFloat())
+            maxHeight = max(maxHeight, view.layoutParams.height.toFloat())
+
+            val lp =
+                if (maxHeight <= 0 || maxWidth <= 0 || targetRegion == null) {
+                    // No specified width/height. Just match parent size.
+                    FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+                } else {
+                    // Scale to fit in targetRegion based on largest child elements.
+                    val ratio = maxWidth / maxHeight
+                    val targetRatio = targetRegion.width() / targetRegion.height().toFloat()
+                    val scale =
+                        if (ratio > targetRatio) targetRegion.width() / maxWidth
+                        else targetRegion.height() / maxHeight
+
+                    FrameLayout.LayoutParams(
+                        (maxWidth * scale).toInt(),
+                        (maxHeight * scale).toInt(),
+                    )
+                }
+
+            lp.gravity = Gravity.CENTER
+            view.layoutParams = lp
+            targetRegion?.let {
+                val (xDiff, yDiff) = computeLayoutDiff(view, it, isLargeClock)
+                view.translationX = xDiff
+                view.translationY = yDiff
+            }
+        }
+
+        override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
+
+        override fun onWeatherDataChanged(data: WeatherData) {
+            layerController.events.onWeatherDataChanged(data)
+        }
+
+        override fun onAlarmDataChanged(data: AlarmData) {
+            layerController.events.onAlarmDataChanged(data)
+        }
+
+        override fun onZenDataChanged(data: ZenData) {
+            layerController.events.onZenDataChanged(data)
+        }
+    }
+
+    override val animations =
+        object : ClockAnimations {
+            override fun enter() {
+                layerController.animations.enter()
+            }
+
+            override fun doze(fraction: Float) {
+                layerController.animations.doze(fraction)
+            }
+
+            override fun fold(fraction: Float) {
+                layerController.animations.fold(fraction)
+            }
+
+            override fun charge() {
+                layerController.animations.charge()
+            }
+
+            override fun onPickerCarouselSwiping(swipingFraction: Float) {
+                face.pickerScale?.let {
+                    view.scaleX = swipingFraction * (1 - it.scaleX) + it.scaleX
+                    view.scaleY = swipingFraction * (1 - it.scaleY) + it.scaleY
+                }
+                if (isLargeClock && !(view as FlexClockView).isAlignedWithScreen()) {
+                    view.translationY = keyguardLargeClockTopMargin / 2F * swipingFraction
+                }
+                layerController.animations.onPickerCarouselSwiping(swipingFraction)
+                view.invalidate()
+            }
+
+            override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {
+                layerController.animations.onPositionUpdated(fromLeft, direction, fraction)
+            }
+
+            override fun onPositionUpdated(distance: Float, fraction: Float) {
+                layerController.animations.onPositionUpdated(distance, fraction)
+            }
+        }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockFaceController.kt
deleted file mode 100644
index ef398d1..0000000
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockFaceController.kt
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.clocks
-
-import android.content.Context
-import android.content.res.Resources
-import android.graphics.Rect
-import android.view.Gravity
-import android.view.View
-import android.view.ViewGroup.LayoutParams.MATCH_PARENT
-import android.widget.FrameLayout
-import com.android.systemui.log.core.MessageBuffer
-import com.android.systemui.plugins.clocks.AlarmData
-import com.android.systemui.plugins.clocks.ClockAnimations
-import com.android.systemui.plugins.clocks.ClockEvents
-import com.android.systemui.plugins.clocks.ClockFaceConfig
-import com.android.systemui.plugins.clocks.ClockFaceController
-import com.android.systemui.plugins.clocks.ClockFaceEvents
-import com.android.systemui.plugins.clocks.ClockFaceLayout
-import com.android.systemui.plugins.clocks.ClockReactiveSetting
-import com.android.systemui.plugins.clocks.ClockTickRate
-import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
-import com.android.systemui.plugins.clocks.WeatherData
-import com.android.systemui.plugins.clocks.ZenData
-import com.android.systemui.shared.clocks.view.DigitalClockFaceView
-import java.util.Locale
-import java.util.TimeZone
-import kotlin.math.max
-
-interface ClockEventUnion : ClockEvents, ClockFaceEvents
-
-class SimpleClockFaceController(
-    ctx: Context,
-    val assets: AssetLoader,
-    face: ClockFace,
-    isLargeClock: Boolean,
-    messageBuffer: MessageBuffer,
-) : ClockFaceController {
-    override val view: View
-    override val config: ClockFaceConfig by lazy {
-        ClockFaceConfig(
-            hasCustomWeatherDataDisplay = layers.any { it.config.hasCustomWeatherDataDisplay },
-            hasCustomPositionUpdatedAnimation =
-                layers.any { it.config.hasCustomPositionUpdatedAnimation },
-            tickRate = getTickRate(),
-            useCustomClockScene = layers.any { it.config.useCustomClockScene },
-        )
-    }
-
-    val layers = mutableListOf<SimpleClockLayerController>()
-
-    val timespecHandler = DigitalTimespecHandler(DigitalTimespec.TIME_FULL_FORMAT, "hh:mm")
-
-    init {
-        val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
-        lp.gravity = Gravity.CENTER
-        view =
-            if (face.layers.size == 1) {
-                // Optimize a clocks with a single layer by excluding the face level view group. We
-                // expect the view container from the host process to always be a FrameLayout.
-                val layer = face.layers[0]
-                val controller =
-                    SimpleClockLayerController.Factory.create(
-                        ctx,
-                        assets,
-                        layer,
-                        isLargeClock,
-                        messageBuffer,
-                    )
-                layers.add(controller)
-                controller.view.layoutParams = lp
-                controller.view
-            } else {
-                // For multiple views, we use an intermediate RelativeLayout so that we can do some
-                // intelligent laying out between the children views.
-                val group = SimpleClockRelativeLayout(ctx, face.faceLayout)
-                group.layoutParams = lp
-                group.gravity = Gravity.CENTER
-                group.clipChildren = false
-                for (layer in face.layers) {
-                    face.faceLayout?.let {
-                        if (layer is DigitalHandLayer) {
-                            layer.faceLayout = it
-                        }
-                    }
-                    val controller =
-                        SimpleClockLayerController.Factory.create(
-                            ctx,
-                            assets,
-                            layer,
-                            isLargeClock,
-                            messageBuffer,
-                        )
-                    group.addView(controller.view)
-                    layers.add(controller)
-                }
-                group
-            }
-    }
-
-    override val layout: ClockFaceLayout =
-        DefaultClockFaceLayout(view).apply {
-            views[0].id =
-                if (isLargeClock) {
-                    assets.getResourcesId("lockscreen_clock_view_large")
-                } else {
-                    assets.getResourcesId("lockscreen_clock_view")
-                }
-        }
-
-    override val events =
-        object : ClockEventUnion {
-            override var isReactiveTouchInteractionEnabled = false
-                get() = field
-                set(value) {
-                    field = value
-                    layers.forEach { it.events.isReactiveTouchInteractionEnabled = value }
-                }
-
-            override fun onTimeTick() {
-                timespecHandler.updateTime()
-                if (
-                    config.tickRate == ClockTickRate.PER_MINUTE ||
-                        view.contentDescription != timespecHandler.getContentDescription()
-                ) {
-                    view.contentDescription = timespecHandler.getContentDescription()
-                }
-                layers.forEach { it.faceEvents.onTimeTick() }
-            }
-
-            override fun onTimeZoneChanged(timeZone: TimeZone) {
-                timespecHandler.timeZone = timeZone
-                layers.forEach { it.events.onTimeZoneChanged(timeZone) }
-            }
-
-            override fun onTimeFormatChanged(is24Hr: Boolean) {
-                timespecHandler.is24Hr = is24Hr
-                layers.forEach { it.events.onTimeFormatChanged(is24Hr) }
-            }
-
-            override fun onLocaleChanged(locale: Locale) {
-                timespecHandler.updateLocale(locale)
-                layers.forEach { it.events.onLocaleChanged(locale) }
-            }
-
-            override fun onFontSettingChanged(fontSizePx: Float) {
-                layers.forEach { it.faceEvents.onFontSettingChanged(fontSizePx) }
-            }
-
-            override fun onColorPaletteChanged(resources: Resources) {
-                layers.forEach {
-                    it.events.onColorPaletteChanged(resources)
-                    it.updateColors()
-                }
-            }
-
-            override fun onSeedColorChanged(seedColor: Int?) {
-                layers.forEach {
-                    it.events.onSeedColorChanged(seedColor)
-                    it.updateColors()
-                }
-            }
-
-            override fun onRegionDarknessChanged(isRegionDark: Boolean) {
-                layers.forEach { it.faceEvents.onRegionDarknessChanged(isRegionDark) }
-            }
-
-            override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {}
-
-            /**
-             * targetRegion passed to all customized clock applies counter translationY of
-             * KeyguardStatusView and keyguard_large_clock_top_margin from default clock
-             */
-            override fun onTargetRegionChanged(targetRegion: Rect?) {
-                // When a clock needs to be aligned with screen, like weather clock
-                // it needs to offset back the translation of keyguard_large_clock_top_margin
-                if (view is DigitalClockFaceView && view.isAlignedWithScreen()) {
-                    val topMargin = getKeyguardLargeClockTopMargin(assets)
-                    targetRegion?.let {
-                        val (_, yDiff) = computeLayoutDiff(view, it, isLargeClock)
-                        // In LS, we use yDiff to counter translate
-                        // the translation of KeyguardLargeClockTopMargin
-                        // With the targetRegion passed from picker,
-                        // we will have yDiff = 0, no translation is needed for weather clock
-                        if (yDiff.toInt() != 0) view.translationY = yDiff - topMargin / 2
-                    }
-                    return
-                }
-
-                var maxWidth = 0f
-                var maxHeight = 0f
-
-                for (layer in layers) {
-                    layer.faceEvents.onTargetRegionChanged(targetRegion)
-                    maxWidth = max(maxWidth, layer.view.layoutParams.width.toFloat())
-                    maxHeight = max(maxHeight, layer.view.layoutParams.height.toFloat())
-                }
-
-                val lp =
-                    if (maxHeight <= 0 || maxWidth <= 0 || targetRegion == null) {
-                        // No specified width/height. Just match parent size.
-                        FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
-                    } else {
-                        // Scale to fit in targetRegion based on largest child elements.
-                        val ratio = maxWidth / maxHeight
-                        val targetRatio = targetRegion.width() / targetRegion.height().toFloat()
-                        val scale =
-                            if (ratio > targetRatio) targetRegion.width() / maxWidth
-                            else targetRegion.height() / maxHeight
-
-                        FrameLayout.LayoutParams(
-                            (maxWidth * scale).toInt(),
-                            (maxHeight * scale).toInt(),
-                        )
-                    }
-
-                lp.gravity = Gravity.CENTER
-                view.layoutParams = lp
-                targetRegion?.let {
-                    val (xDiff, yDiff) = computeLayoutDiff(view, it, isLargeClock)
-                    view.translationX = xDiff
-                    view.translationY = yDiff
-                }
-            }
-
-            override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
-
-            override fun onWeatherDataChanged(data: WeatherData) {
-                layers.forEach { it.events.onWeatherDataChanged(data) }
-            }
-
-            override fun onAlarmDataChanged(data: AlarmData) {
-                layers.forEach { it.events.onAlarmDataChanged(data) }
-            }
-
-            override fun onZenDataChanged(data: ZenData) {
-                layers.forEach { it.events.onZenDataChanged(data) }
-            }
-        }
-
-    override val animations =
-        object : ClockAnimations {
-            override fun enter() {
-                layers.forEach { it.animations.enter() }
-            }
-
-            override fun doze(fraction: Float) {
-                layers.forEach { it.animations.doze(fraction) }
-            }
-
-            override fun fold(fraction: Float) {
-                layers.forEach { it.animations.fold(fraction) }
-            }
-
-            override fun charge() {
-                layers.forEach { it.animations.charge() }
-            }
-
-            override fun onPickerCarouselSwiping(swipingFraction: Float) {
-                face.pickerScale?.let {
-                    view.scaleX = swipingFraction * (1 - it.scaleX) + it.scaleX
-                    view.scaleY = swipingFraction * (1 - it.scaleY) + it.scaleY
-                }
-                if (!(view is DigitalClockFaceView && view.isAlignedWithScreen())) {
-                    val topMargin = getKeyguardLargeClockTopMargin(assets)
-                    view.translationY = topMargin / 2F * swipingFraction
-                }
-                layers.forEach { it.animations.onPickerCarouselSwiping(swipingFraction) }
-                view.invalidate()
-            }
-
-            override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {
-                layers.forEach { it.animations.onPositionUpdated(fromLeft, direction, fraction) }
-            }
-
-            override fun onPositionUpdated(distance: Float, fraction: Float) {
-                layers.forEach { it.animations.onPositionUpdated(distance, fraction) }
-            }
-        }
-
-    private fun getTickRate(): ClockTickRate {
-        var tickRate = ClockTickRate.PER_MINUTE
-        for (layer in layers) {
-            if (layer.config.tickRate.value < tickRate.value) {
-                tickRate = layer.config.tickRate
-            }
-        }
-        return tickRate
-    }
-
-    private fun getKeyguardLargeClockTopMargin(assets: AssetLoader): Int {
-        val topMarginRes =
-            assets.resolveResourceId(null, "dimen", "keyguard_large_clock_top_margin")
-        if (topMarginRes != null) {
-            val (res, id) = topMarginRes
-            return res.getDimensionPixelSize(id)
-        }
-        return 0
-    }
-}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
index f71543e..5d1a2db 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt
@@ -16,25 +16,12 @@
 
 package com.android.systemui.shared.clocks
 
-import android.content.Context
 import android.view.View
 import androidx.annotation.VisibleForTesting
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.ClockAnimations
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFaceConfig
 import com.android.systemui.plugins.clocks.ClockFaceEvents
-import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
-import kotlin.reflect.KClass
-
-typealias LayerControllerConstructor =
-    (
-        ctx: Context,
-        assets: AssetLoader,
-        layer: ClockLayer,
-        isLargeClock: Boolean,
-        messageBuffer: MessageBuffer,
-    ) -> SimpleClockLayerController
 
 interface SimpleClockLayerController {
     val view: View
@@ -48,55 +35,4 @@
     // Called immediately after either onColorPaletteChanged or onSeedColorChanged is called.
     // Provided for convience to not duplicate color update logic after state updated.
     fun updateColors() {}
-
-    companion object Factory {
-        val constructorMap = mutableMapOf<Pair<KClass<*>, KClass<*>?>, LayerControllerConstructor>()
-
-        internal inline fun <reified TLayer> registerConstructor(
-            noinline constructor: LayerControllerConstructor,
-        ) where TLayer : ClockLayer {
-            constructorMap[Pair(TLayer::class, null)] = constructor
-        }
-
-        inline fun <reified TLayer, reified TStyle> registerTextConstructor(
-            noinline constructor: LayerControllerConstructor,
-        ) where TLayer : ClockLayer, TStyle : TextStyle {
-            constructorMap[Pair(TLayer::class, TStyle::class)] = constructor
-        }
-
-        init {
-            registerConstructor<ComposedDigitalHandLayer>(::ComposedDigitalLayerController)
-            registerTextConstructor<DigitalHandLayer, FontTextStyle>(::createSimpleDigitalLayer)
-        }
-
-        private fun createSimpleDigitalLayer(
-            ctx: Context,
-            assets: AssetLoader,
-            layer: ClockLayer,
-            isLargeClock: Boolean,
-            messageBuffer: MessageBuffer
-        ): SimpleClockLayerController {
-            val view = SimpleDigitalClockTextView(ctx, messageBuffer)
-            return SimpleDigitalHandLayerController(
-                ctx,
-                assets,
-                layer as DigitalHandLayer,
-                view,
-                messageBuffer
-            )
-        }
-
-        fun create(
-            ctx: Context,
-            assets: AssetLoader,
-            layer: ClockLayer,
-            isLargeClock: Boolean,
-            messageBuffer: MessageBuffer
-        ): SimpleClockLayerController {
-            val styleClass = if (layer is DigitalHandLayer) layer.style::class else null
-            val key = Pair(layer::class, styleClass)
-            return constructorMap[key]?.invoke(ctx, assets, layer, isLargeClock, messageBuffer)
-                ?: throw IllegalArgumentException("Unrecognized ClockLayer type: $key")
-        }
-    }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index a3240f8..ce1eae4 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -42,7 +42,8 @@
 
 open class SimpleDigitalHandLayerController<T>(
     private val ctx: Context,
-    private val assets: AssetLoader,
+    private val resources: Resources,
+    private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
     private val layer: DigitalHandLayer,
     override val view: T,
     messageBuffer: MessageBuffer,
@@ -68,7 +69,7 @@
         view.layoutParams =
             RelativeLayout.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT
+                ViewGroup.LayoutParams.WRAP_CONTENT,
             )
         if (layer.alignment != null) {
             layer.alignment.verticalAlignment?.let { view.verticalAlignment = it }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
index eb72346..81efcb9 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.shared.clocks.LogUtil
 import java.util.Locale
 
+// TODO(b/364680879): Merge w/ only subclass FlexClockView
 abstract class DigitalClockFaceView(ctx: Context, messageBuffer: MessageBuffer) : FrameLayout(ctx) {
     protected val logger = Logger(messageBuffer, this::class.simpleName!!)
         get() = field ?: LogUtil.FALLBACK_INIT_LOGGER
@@ -140,7 +141,6 @@
     open val useCustomClockScene
         get() = false
 
-    // TODO: implement ClockEventUnion?
     open fun onLocaleChanged(locale: Locale) {}
 
     open fun onWeatherDataChanged(data: WeatherData) {}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index c29c8da..25b2ad7 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -35,7 +35,7 @@
 
 fun clamp(value: Float, minVal: Float, maxVal: Float): Float = max(min(value, maxVal), minVal)
 
-class FlexClockView(context: Context, val assetLoader: AssetLoader, messageBuffer: MessageBuffer) :
+class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: MessageBuffer) :
     DigitalClockFaceView(context, messageBuffer) {
     override var digitalClockTextViewMap = mutableMapOf<Int, SimpleDigitalClockTextView>()
     val digitLeftTopMap = mutableMapOf<Int, Point>()
@@ -57,11 +57,9 @@
     private var prevY = 0f
     private var isDown = false
 
-    // TODO(b/340253296): Genericize; json spec
     private var wght = 603f
     private var wdth = 100f
 
-    // TODO(b/340253296): Json spec
     private val MAX_WGHT = 950f
     private val MIN_WGHT = 50f
     private val WGHT_SCALE = 0.5f
@@ -71,7 +69,6 @@
     private val WDTH_SCALE = 0.2f
 
     override fun onTouchEvent(evt: MotionEvent): Boolean {
-        // TODO(b/340253296): implement on DigitalClockFaceView?
         if (!isReactiveTouchInteractionEnabled) {
             return super.onTouchEvent(evt)
         }
@@ -94,12 +91,11 @@
                 prevX = evt.x
                 prevY = evt.y
 
-                // TODO(b/340253296): Genericize; json spec
                 val fvar = "'wght' $wght, 'wdth' $wdth, 'opsz' 144, 'ROND' 100"
                 digitalClockTextViewMap.forEach { (_, view) ->
                     val textStyle = view.textStyle as FontTextStyle
                     textStyle.fontVariation = fvar
-                    view.applyStyles(assetLoader, textStyle, view.aodStyle)
+                    view.applyStyles(assets, textStyle, view.aodStyle)
                 }
 
                 requestLayout()
diff --git a/packages/SystemUI/docs/scene.md b/packages/SystemUI/docs/scene.md
index 234c7a0..bf15b4f 100644
--- a/packages/SystemUI/docs/scene.md
+++ b/packages/SystemUI/docs/scene.md
@@ -63,7 +63,7 @@
 NOTE: in case these instructions become stale and don't actually enable the
 framework, please make sure `SceneContainerFlag.isEnabled` in the
 [`SceneContainerFlag.kt`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt)
-file evalutes to `true`.
+file evaluates to `true`.
 
 1.  Set a collection of **aconfig flags** to `true` by running the following
     commands:
@@ -73,7 +73,6 @@
     $ adb shell device_config override systemui com.android.systemui.migrate_clocks_to_blueprint true
     $ adb shell device_config override systemui com.android.systemui.notification_avalanche_throttle_hun true
     $ adb shell device_config override systemui com.android.systemui.predictive_back_sysui true
-    $ adb shell device_config override systemui com.android.systemui.device_entry_udfps_refactor true
     $ adb shell device_config override systemui com.android.systemui.scene_container true
     ```
 2.  **Restart** System UI by issuing the following command:
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index 2bb9e68..00c5577 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -156,8 +156,12 @@
         when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
                 .thenReturn(INVISIBLE);
 
-        when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
-        when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
+        when(mView
+                .findViewById(com.android.systemui.customization.R.id.lockscreen_clock_view_large))
+                .thenReturn(mLargeClockFrame);
+        when(mView
+                .findViewById(com.android.systemui.customization.R.id.lockscreen_clock_view))
+                .thenReturn(mSmallClockFrame);
         when(mSmallClockView.getContext()).thenReturn(getContext());
         when(mLargeClockView.getContext()).thenReturn(getContext());
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 0bf9d12..4ed5fd0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -113,8 +113,10 @@
         });
         mKeyguardClockSwitch =
                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
-        mSmallClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
-        mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large);
+        mSmallClockFrame = mKeyguardClockSwitch
+                .findViewById(com.android.systemui.customization.R.id.lockscreen_clock_view);
+        mLargeClockFrame = mKeyguardClockSwitch
+                .findViewById(com.android.systemui.customization.R.id.lockscreen_clock_view_large);
         mStatusArea = mKeyguardClockSwitch.findViewById(R.id.keyguard_status_area);
         mKeyguardClockSwitch.mChildrenAreLaidOut = true;
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
index 2e41246..245388c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
@@ -17,10 +17,10 @@
 package com.android.keyguard
 
 import android.view.View
-import android.view.ViewGroup
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -88,7 +88,7 @@
         underTest.statusViewCentered = true
 
         val view = View(context)
-        whenever(keyguardRootView.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(
+        whenever(keyguardRootView.findViewById<View>(customR.id.lockscreen_clock_view_large)).thenReturn(
             view
         )
 
@@ -110,7 +110,7 @@
         whenever(statusBarStateController.getState()).thenReturn(SHADE)
 
         val view = View(context)
-        whenever(keyguardRootView.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(
+        whenever(keyguardRootView.findViewById<View>(customR.id.lockscreen_clock_view_large)).thenReturn(
             view
         )
 
@@ -134,7 +134,7 @@
         val view = View(context)
         whenever(
             notificationShadeWindowView
-                .findViewById<View>(R.id.lockscreen_clock_view_large)
+                .findViewById<View>(customR.id.lockscreen_clock_view_large)
         ).thenReturn(view)
 
         progressListener.onTransitionStarted()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
deleted file mode 100644
index 13306be..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2023 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.biometrics
-
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.phone.SystemUIDialogManager
-import org.junit.Assert.assertFalse
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.junit.MockitoJUnit
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-@TestableLooper.RunWithLooper
-class UdfpsBpViewControllerTest : SysuiTestCase() {
-
-    @JvmField @Rule var rule = MockitoJUnit.rule()
-
-    @Mock lateinit var udfpsBpView: UdfpsBpView
-    @Mock lateinit var statusBarStateController: StatusBarStateController
-    @Mock lateinit var shadeInteractor: ShadeInteractor
-    @Mock lateinit var systemUIDialogManager: SystemUIDialogManager
-    @Mock lateinit var dumpManager: DumpManager
-    @Mock lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
-
-    private lateinit var udfpsBpViewController: UdfpsBpViewController
-
-    @Before
-    fun setup() {
-        udfpsBpViewController =
-            UdfpsBpViewController(
-                udfpsBpView,
-                statusBarStateController,
-                shadeInteractor,
-                systemUIDialogManager,
-                dumpManager,
-                udfpsOverlayInteractor,
-            )
-    }
-
-    @TestableLooper.RunWithLooper(setAsMainLooper = true)
-    @Test
-    fun testShouldNeverPauseAuth() {
-        assertFalse(udfpsBpViewController.shouldPauseAuth())
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 437a4b3..21c6583 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,34 +16,17 @@
 
 package com.android.systemui.biometrics;
 
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_UP;
-
-import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
-import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.graphics.Rect;
-import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.BiometricRequestConstants;
 import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
@@ -58,13 +41,9 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.testing.TestableLooper.RunWithLooper;
-import android.util.Pair;
-import android.view.HapticFeedbackConstants;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityManager;
 
@@ -75,15 +54,11 @@
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityTransitionAnimator;
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
-import com.android.systemui.biometrics.udfps.InteractionEvent;
-import com.android.systemui.biometrics.udfps.NormalizedTouchData;
 import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
-import com.android.systemui.biometrics.udfps.TouchProcessorResult;
 import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayViewModel;
 import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -102,7 +77,6 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.power.shared.model.WakeSleepReason;
 import com.android.systemui.power.shared.model.WakefulnessState;
-import com.android.systemui.res.R;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.VibratorHelper;
@@ -130,7 +104,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
-import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -204,16 +177,6 @@
     private FeatureFlags mFeatureFlags;
     // Stuff for configuring mocks
     @Mock
-    private UdfpsView mUdfpsView;
-    @Mock
-    private UdfpsBpView mBpView;
-    @Mock
-    private UdfpsFpmEmptyView mFpmEmptyView;
-    @Mock
-    private UdfpsKeyguardViewLegacy mKeyguardView;
-    private final UdfpsAnimationViewController mUdfpsKeyguardViewController =
-            mock(UdfpsKeyguardViewControllerLegacy.class);
-    @Mock
     private SystemUIDialogManager mSystemUIDialogManager;
     @Mock
     private ActivityTransitionAnimator mActivityTransitionAnimator;
@@ -241,8 +204,6 @@
     @Captor
     private ArgumentCaptor<View> mViewCaptor;
     @Captor
-    private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
-    @Captor
     private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor;
     @Captor
     private ArgumentCaptor<Runnable> mOnDisplayConfiguredCaptor;
@@ -287,18 +248,9 @@
         mContext.getOrCreateTestableResources()
                 .addOverride(com.android.internal.R.bool.config_ignoreUdfpsVote, false);
 
-        when(mLayoutInflater.inflate(R.layout.udfps_view, null, false))
-                .thenReturn(mUdfpsView);
-        when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view_legacy, null))
-                .thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
-        when(mLayoutInflater.inflate(R.layout.udfps_bp_view, null))
-                .thenReturn(mBpView);
-        when(mLayoutInflater.inflate(R.layout.udfps_fpm_empty_view, null))
-                .thenReturn(mFpmEmptyView);
         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
         when(mSessionTracker.getSessionId(anyInt())).thenReturn(
                 (new InstanceIdSequence(1 << 20)).newInstanceId());
-        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
 
         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
         componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
@@ -327,7 +279,6 @@
         // Create a fake background executor.
         mBiometricExecutor = new FakeExecutor(new FakeSystemClock());
 
-        mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         initUdfpsController(mOpticalProps);
     }
 
@@ -349,7 +300,6 @@
                 mFalsingManager,
                 mPowerManager,
                 mAccessibilityManager,
-                mLockscreenShadeTransitionController,
                 mScreenLifecycle,
                 mVibrator,
                 mUdfpsHapticsSimulator,
@@ -390,101 +340,6 @@
     }
 
     @Test
-    public void dozeTimeTick() throws RemoteException {
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-        mUdfpsController.dozeTimeTick();
-        verify(mUdfpsView).dozeTimeTick();
-    }
-
-    @Test
-    public void onActionDownTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
-        // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
-        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
-
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent downEvent = obtainMotionEvent(ACTION_DOWN, 0, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // THEN notify keyguard authenticate to dismiss the keyguard
-        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
-    }
-
-    @Test
-    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
-        onActionMoveTouch_whenCanDismissLockScreen_entersDevice(false /* stale */);
-    }
-
-    @Test
-    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()
-            throws RemoteException {
-        onActionMoveTouch_whenCanDismissLockScreen_entersDevice(true /* stale */);
-    }
-
-    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)
-            throws RemoteException {
-        // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
-        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
-
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-
-        // WHEN ACTION_MOVE is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        if (stale) {
-            mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId);
-            mFgExecutor.runAllReady();
-        }
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
-
-        // THEN notify keyguard authenticate to dismiss the keyguard
-        verify(mStatusBarKeyguardViewManager, stale ? never() : times(1))
-                .notifyKeyguardAuthenticated(anyBoolean());
-    }
-
-    @Test
-    public void onMultipleTouch_whenCanDismissLockScreen_entersDeviceOnce() throws RemoteException {
-        // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
-        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
-
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UNCHANGED, false);
-
-        // GIVEN that the overlay is showing
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.second);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
-
-        // THEN notify keyguard authenticate to dismiss the keyguard
-        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
-    }
-
-    @Test
     public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
         // GIVEN overlay was showing and the udfps bouncer is showing
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
@@ -524,61 +379,6 @@
     }
 
     @Test
-    public void updateOverlayParams_recreatesOverlay_ifParamsChanged() throws Exception {
-        final Rect[] sensorBounds = new Rect[]{new Rect(10, 10, 20, 20), new Rect(5, 5, 25, 25)};
-        final int[] displayWidth = new int[]{1080, 1440};
-        final int[] displayHeight = new int[]{1920, 2560};
-        final float[] scaleFactor = new float[]{1f, displayHeight[1] / (float) displayHeight[0]};
-        final int[] rotation = new int[]{Surface.ROTATION_0, Surface.ROTATION_90};
-        final UdfpsOverlayParams oldParams = new UdfpsOverlayParams(sensorBounds[0],
-                sensorBounds[0], displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0],
-                FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
-
-        for (int i1 = 0; i1 <= 1; ++i1) {
-            for (int i2 = 0; i2 <= 1; ++i2) {
-                for (int i3 = 0; i3 <= 1; ++i3) {
-                    for (int i4 = 0; i4 <= 1; ++i4) {
-                        for (int i5 = 0; i5 <= 1; ++i5) {
-                            final UdfpsOverlayParams newParams = new UdfpsOverlayParams(
-                                    sensorBounds[i1], sensorBounds[i1], displayWidth[i2],
-                                    displayHeight[i3], scaleFactor[i4], rotation[i5],
-                                    FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
-
-                            if (newParams.equals(oldParams)) {
-                                continue;
-                            }
-
-                            // Initialize the overlay with old parameters.
-                            mUdfpsController.updateOverlayParams(mOpticalProps, oldParams);
-
-                            // Show the overlay.
-                            reset(mWindowManager);
-                            mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID,
-                                    mOpticalProps.sensorId,
-                                    BiometricRequestConstants.REASON_ENROLL_ENROLLING,
-                                    mUdfpsOverlayControllerCallback);
-
-                            mFgExecutor.runAllReady();
-                            verify(mWindowManager).addView(mViewCaptor.capture(), any());
-                            when(mViewCaptor.getValue().getParent())
-                                    .thenReturn(mock(ViewGroup.class));
-
-                            // Update overlay parameters.
-                            reset(mWindowManager);
-                            mUdfpsController.updateOverlayParams(mOpticalProps, newParams);
-                            mFgExecutor.runAllReady();
-
-                            // Ensure the overlay was recreated.
-                            verify(mWindowManager).removeView(any());
-                            verify(mWindowManager).addView(any(), any());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    @Test
     public void updateOverlayParams_doesNothing_ifParamsDidntChange() throws Exception {
         final Rect sensorBounds = new Rect(10, 10, 20, 20);
         final int displayWidth = 1080;
@@ -595,7 +395,6 @@
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                 BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
-        verify(mWindowManager).addView(any(), any());
 
         // Update overlay with the same parameters.
         mUdfpsController.updateOverlayParams(mOpticalProps,
@@ -606,870 +405,4 @@
         // Ensure the overlay was not recreated.
         verify(mWindowManager, never()).removeView(any());
     }
-
-    private static MotionEvent obtainMotionEvent(int action, float x, float y, float minor,
-            float major) {
-        MotionEvent.PointerProperties pp = new MotionEvent.PointerProperties();
-        pp.id = 1;
-        MotionEvent.PointerCoords pc = new MotionEvent.PointerCoords();
-        pc.x = x;
-        pc.y = y;
-        pc.touchMinor = minor;
-        pc.touchMajor = major;
-        return MotionEvent.obtain(0, 0, action, 1, new MotionEvent.PointerProperties[]{pp},
-                new MotionEvent.PointerCoords[]{pc}, 0, 0, 1f, 1f, 0, 0, 0, 0);
-    }
-
-    private static class TestParams {
-        public final FingerprintSensorPropertiesInternal sensorProps;
-
-        TestParams(FingerprintSensorPropertiesInternal sensorProps) {
-            this.sensorProps = sensorProps;
-        }
-    }
-
-    private void runWithAllParams(ThrowingConsumer<TestParams> testParamsConsumer) {
-        for (FingerprintSensorPropertiesInternal sensorProps : List.of(mOpticalProps,
-                mUltrasonicProps)) {
-            initUdfpsController(sensorProps);
-            testParamsConsumer.accept(new TestParams(sensorProps));
-        }
-    }
-
-    @Test
-    public void onTouch_propagatesTouchInNativeOrientationAndResolution() {
-        runWithAllParams(
-                this::onTouch_propagatesTouchInNativeOrientationAndResolutionParameterized);
-    }
-
-    private void onTouch_propagatesTouchInNativeOrientationAndResolutionParameterized(
-            TestParams testParams) throws RemoteException {
-        reset(mUdfpsView);
-        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
-
-        final Rect sensorBounds = new Rect(1000, 1900, 1080, 1920); // Bottom right corner.
-        final int pointerId = 0;
-        final int displayWidth = 1080;
-        final int displayHeight = 1920;
-        final float scaleFactor = 1f; // This means the native resolution is 1440x2560.
-        final float touchMinor = 10f;
-        final float touchMajor = 20f;
-        final float orientation = 30f;
-
-        // Expecting a touch at the very bottom right corner in native orientation and resolution.
-        final float expectedX = displayWidth / scaleFactor;
-        final float expectedY = displayHeight / scaleFactor;
-        final float expectedMinor = touchMinor / scaleFactor;
-        final float expectedMajor = touchMajor / scaleFactor;
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-
-        // GIVEN a valid touch on sensor
-        NormalizedTouchData touchData = new NormalizedTouchData(pointerId, displayWidth,
-                displayHeight, touchMinor, touchMajor, orientation, 0L, 0L);
-        TouchProcessorResult processorDownResult = new TouchProcessorResult.ProcessedTouch(
-                InteractionEvent.DOWN, 1, touchData);
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorDownResult);
-
-        // Show the overlay.
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
-        // Test ROTATION_0
-        mUdfpsController.updateOverlayParams(testParams.sensorProps,
-                new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
-                        scaleFactor, Surface.ROTATION_0,
-                        FingerprintSensorProperties.TYPE_UDFPS_OPTICAL));
-        MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor,
-                touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
-                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
-                anyBoolean());
-
-        // Test ROTATION_90
-        reset(mFingerprintManager);
-        mUdfpsController.updateOverlayParams(testParams.sensorProps,
-                new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
-                        scaleFactor, Surface.ROTATION_90,
-                        FingerprintSensorProperties.TYPE_UDFPS_OPTICAL));
-        event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
-                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
-                anyBoolean());
-
-        // Test ROTATION_270
-        reset(mFingerprintManager);
-        mUdfpsController.updateOverlayParams(testParams.sensorProps,
-                new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
-                        scaleFactor, Surface.ROTATION_270,
-                        FingerprintSensorProperties.TYPE_UDFPS_OPTICAL));
-        event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
-                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
-                anyBoolean());
-
-        // Test ROTATION_180
-        reset(mFingerprintManager);
-        mUdfpsController.updateOverlayParams(testParams.sensorProps,
-                new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
-                        scaleFactor, Surface.ROTATION_180,
-                        FingerprintSensorProperties.TYPE_UDFPS_OPTICAL));
-        // ROTATION_180 is not supported. It should be treated like ROTATION_0.
-        event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
-                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
-                anyBoolean());
-    }
-
-    @Test
-    public void fingerDown() {
-        runWithAllParams(this::fingerDownParameterized);
-    }
-
-    private void fingerDownParameterized(TestParams testParams) throws RemoteException {
-        reset(mUdfpsView, mFingerprintManager, mLatencyTracker,
-                mKeyguardUpdateMonitor);
-        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
-
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
-                InteractionEvent.DOWN, 1 /* pointerId */, touchData);
-
-        initUdfpsController(testParams.sensorProps);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        // WHEN ACTION_DOWN is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDown);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // THEN the touch provider is notified about onPointerDown.
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
-
-        // AND display configuration begins
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-            verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture());
-        } else {
-            verify(mLatencyTracker, never()).onActionStart(
-                    eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-            verify(mUdfpsView, never()).configureDisplay(any());
-        }
-        verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            // AND onDisplayConfigured notifies FingerprintManager about onUiReady
-            mOnDisplayConfiguredCaptor.getValue().run();
-            mBiometricExecutor.runAllReady();
-            InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
-            inOrder.verify(mFingerprintManager).onUdfpsUiEvent(
-                    eq(FingerprintManager.UDFPS_UI_READY), eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId));
-            inOrder.verify(mLatencyTracker).onActionEnd(
-                    eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-        } else {
-            verify(mFingerprintManager, never()).onUdfpsUiEvent(
-                    eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
-            verify(mLatencyTracker, never()).onActionEnd(
-                    eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-        }
-    }
-
-    @Test
-    public void aodInterrupt() {
-        runWithAllParams(this::aodInterruptParameterized);
-    }
-
-    private void aodInterruptParameterized(TestParams testParams) throws RemoteException {
-        mUdfpsController.cancelAodSendFingerUpAction();
-        reset(mUdfpsView, mFingerprintManager, mKeyguardUpdateMonitor);
-        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
-        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
-
-        // GIVEN that the overlay is showing and screen is on and fp is running
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-        // WHEN fingerprint is requested because of AOD interrupt
-        mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
-        mFgExecutor.runAllReady();
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            // THEN display configuration begins
-            // AND onDisplayConfigured notifies FingerprintManager about onUiReady
-            verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture());
-            mOnDisplayConfiguredCaptor.getValue().run();
-        } else {
-            verify(mUdfpsView, never()).configureDisplay(mOnDisplayConfiguredCaptor.capture());
-        }
-        mBiometricExecutor.runAllReady();
-
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
-    }
-
-    @Test
-    public void tryAodSendFingerUp_displayConfigurationChanges() {
-        runWithAllParams(this::cancelAodInterruptParameterized);
-    }
-
-    private void cancelAodInterruptParameterized(TestParams testParams) throws RemoteException {
-        reset(mUdfpsView);
-
-        // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-            // WHEN it is cancelled
-            mUdfpsController.tryAodSendFingerUp();
-            // THEN the display is unconfigured
-            verify(mUdfpsView).unconfigureDisplay();
-        } else {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-            // WHEN it is cancelled
-            mUdfpsController.tryAodSendFingerUp();
-            // THEN the display configuration is unchanged.
-            verify(mUdfpsView, never()).unconfigureDisplay();
-        }
-    }
-
-    @Test
-    public void onFingerUp_displayConfigurationChange() {
-        runWithAllParams(this::onFingerUp_displayConfigurationParameterized);
-    }
-
-    private void onFingerUp_displayConfigurationParameterized(TestParams testParams)
-            throws RemoteException {
-        reset(mUdfpsView);
-        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
-
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-
-        // GIVEN AOD interrupt
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-
-            // WHEN up-action received
-            when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                    touchProcessorResult.second);
-            MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
-            mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
-            mBiometricExecutor.runAllReady();
-            upEvent.recycle();
-            mFgExecutor.runAllReady();
-
-            // THEN the display is unconfigured
-            verify(mUdfpsView).unconfigureDisplay();
-        } else {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-
-            // WHEN up-action received
-            when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                    touchProcessorResult.second);
-            MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
-            mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
-            mBiometricExecutor.runAllReady();
-            upEvent.recycle();
-            mFgExecutor.runAllReady();
-
-            // THEN the display configuration is unchanged.
-            verify(mUdfpsView, never()).unconfigureDisplay();
-        }
-    }
-
-    @Test
-    public void onAcquiredGood_displayConfigurationChange() {
-        runWithAllParams(this::onAcquiredGood_displayConfigurationParameterized);
-    }
-
-    private void onAcquiredGood_displayConfigurationParameterized(TestParams testParams)
-            throws RemoteException {
-        reset(mUdfpsView);
-
-        // GIVEN overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-            // WHEN ACQUIRED_GOOD received
-            mOverlayController.onAcquired(testParams.sensorProps.sensorId,
-                    BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
-            mFgExecutor.runAllReady();
-            // THEN the display is unconfigured
-            verify(mUdfpsView).unconfigureDisplay();
-        } else {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-            // WHEN ACQUIRED_GOOD received
-            mOverlayController.onAcquired(testParams.sensorProps.sensorId,
-                    BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
-            mFgExecutor.runAllReady();
-            // THEN the display configuration is unchanged.
-            verify(mUdfpsView, never()).unconfigureDisplay();
-        }
-    }
-
-    @Test
-    public void aodInterruptTimeout() {
-        runWithAllParams(this::aodInterruptTimeoutParameterized);
-    }
-
-    private void aodInterruptTimeoutParameterized(TestParams testParams) throws RemoteException {
-        reset(mUdfpsView);
-
-        // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
-        mFgExecutor.runAllReady();
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-        } else {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        }
-        // WHEN it times out
-        mFgExecutor.advanceClockToNext();
-        mFgExecutor.runAllReady();
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            // THEN the display is unconfigured.
-            verify(mUdfpsView).unconfigureDisplay();
-        } else {
-            // THEN the display configuration is unchanged.
-            verify(mUdfpsView, never()).unconfigureDisplay();
-        }
-    }
-
-    @Test
-    public void aodInterruptCancelTimeoutActionOnFingerUp() {
-        runWithAllParams(this::aodInterruptCancelTimeoutActionOnFingerUpParameterized);
-    }
-
-    private void aodInterruptCancelTimeoutActionOnFingerUpParameterized(TestParams testParams)
-            throws RemoteException {
-        reset(mUdfpsView);
-        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
-
-        // GIVEN AOD interrupt
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
-        mFgExecutor.runAllReady();
-
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            // Configure UdfpsView to accept the ACTION_UP event
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-        } else {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        }
-
-        // WHEN ACTION_UP is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.second);
-        MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
-        mBiometricExecutor.runAllReady();
-        upEvent.recycle();
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        mFgExecutor.runAllReady();
-
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            // Configure UdfpsView to accept the finger up event
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-        } else {
-            when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        }
-
-        // WHEN it times out
-        mFgExecutor.advanceClockToNext();
-        mFgExecutor.runAllReady();
-
-        if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
-            // THEN the display should be unconfigured once. If the timeout action is not
-            // cancelled, the display would be unconfigured twice which would cause two
-            // FP attempts.
-            verify(mUdfpsView).unconfigureDisplay();
-        } else {
-            verify(mUdfpsView, never()).unconfigureDisplay();
-        }
-    }
-
-    @Test
-    public void aodInterruptScreenOff() {
-        runWithAllParams(this::aodInterruptScreenOffParameterized);
-    }
-
-    private void aodInterruptScreenOffParameterized(TestParams testParams) throws RemoteException {
-        reset(mUdfpsView);
-
-        // GIVEN screen off
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mScreenObserver.onScreenTurnedOff();
-        mFgExecutor.runAllReady();
-
-        // WHEN aod interrupt is received
-        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
-
-        // THEN display doesn't get configured because it's off
-        verify(mUdfpsView, never()).configureDisplay(any());
-    }
-
-    @Test
-    public void aodInterrupt_fingerprintNotRunning() {
-        runWithAllParams(this::aodInterrupt_fingerprintNotRunningParameterized);
-    }
-
-    private void aodInterrupt_fingerprintNotRunningParameterized(TestParams testParams)
-            throws RemoteException {
-        reset(mUdfpsView);
-
-        // GIVEN showing overlay
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-
-        // WHEN aod interrupt is received when the fingerprint service isn't running
-        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
-        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
-
-        // THEN display doesn't get configured because it's off
-        verify(mUdfpsView, never()).configureDisplay(any());
-    }
-
-    @Test
-    public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled() throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, true);
-
-        // WHEN ACTION_HOVER is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
-        MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
-        mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
-        enterEvent.recycle();
-
-        // THEN context click haptic is played
-        verify(mVibrator).performHapticFeedback(
-                any(),
-                eq(HapticFeedbackConstants.CONTEXT_CLICK)
-        );
-    }
-
-    @Test
-    public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // THEN NO haptic played
-        verify(mVibrator, never()).performHapticFeedback(any(), anyInt());
-    }
-
-    @Test
-    public void fingerDown_falsingManagerInformed() throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // THEN falsing manager is informed of the touch
-        verify(mFalsingManager).isFalseTouch(UDFPS_AUTHENTICATION);
-    }
-
-    private Pair<TouchProcessorResult, TouchProcessorResult> givenFingerEvent(
-            InteractionEvent event1, InteractionEvent event2, boolean a11y)
-            throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
-                event1, 1 /* pointerId */, touchData);
-        final TouchProcessorResult processorResultUp = new TouchProcessorResult.ProcessedTouch(
-                event2, 1 /* pointerId */, touchData);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps);
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(a11y);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        if (a11y) {
-            verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
-        } else {
-            verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-        }
-
-        return new Pair<>(processorResultDown, processorResultUp);
-    }
-
-    @Test
-    public void onTouch_forwardToKeyguard() throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
-                InteractionEvent.UNCHANGED, -1 /* pointerOnSensorId */, touchData);
-
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDown);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-
-        // THEN the touch is forwarded to Keyguard
-        verify(mStatusBarKeyguardViewManager).onTouch(downEvent);
-    }
-
-    @Test
-    public void onTouch_pilferPointer() throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UNCHANGED, false);
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent event = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-
-        // WHEN ACTION_MOVE is received after
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.second);
-        event.setAction(ACTION_MOVE);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-
-        // THEN only pilfer once on the initial down
-        verify(mInputManager).pilferPointers(any());
-    }
-
-    @Test
-    public void onTouch_doNotPilferPointer() throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultUnchanged =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.UNCHANGED,
-                        -1 /* pointerId */, touchData);
-
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
-        // WHEN ACTION_DOWN is received and touch is not within sensor
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultUnchanged);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // THEN the touch is NOT pilfered
-        verify(mInputManager, never()).pilferPointers(any());
-    }
-
-    @Test
-    public void onDownTouchReceivedWithoutPreviousUp() throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
-                        -1 /* pointerId */, touchData);
-
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
-        // WHEN ACTION_DOWN is received and touch is within sensor
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDown);
-        MotionEvent firstDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, firstDownEvent);
-        mBiometricExecutor.runAllReady();
-        firstDownEvent.recycle();
-
-        // And another ACTION_DOWN is received without an ACTION_UP before
-        MotionEvent secondDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, secondDownEvent);
-        mBiometricExecutor.runAllReady();
-        secondDownEvent.recycle();
-
-        // THEN the touch is still processed
-        verify(mFingerprintManager, times(2)).onPointerDown(anyLong(), anyInt(), anyInt(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
-                anyBoolean());
-    }
-
-    @Test
-    public void onAodDownAndDownTouchReceived() throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
-                        -1 /* pointerId */, touchData);
-
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
-        // WHEN fingerprint is requested because of AOD interrupt
-        // GIVEN there's been an AoD interrupt
-        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
-        mScreenObserver.onScreenTurnedOn();
-        mUdfpsController.onAodInterrupt(0, 0, 0, 0);
-        mFgExecutor.runAllReady();
-
-        // and an ACTION_DOWN is received and touch is within sensor
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDown);
-        MotionEvent firstDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, firstDownEvent);
-        mBiometricExecutor.runAllReady();
-        firstDownEvent.recycle();
-
-        // THEN the touch is only processed once
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
-                anyBoolean());
-    }
-
-    @Test
-    public void onTouch_pilferPointerWhenAltBouncerShowing()
-            throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.UNCHANGED, InteractionEvent.UP, false);
-
-        // WHEN alternate bouncer is showing
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // WHEN ACTION_DOWN is received and touch is not within sensor
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // THEN the touch is pilfered
-        verify(mInputManager).pilferPointers(any());
-    }
-
-    @Test
-    public void onTouch_doNotProcessTouchWhenPullingUpBouncer()
-            throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.UNCHANGED, InteractionEvent.UP, false);
-
-        // GIVEN a swipe up to bring up primary bouncer is in progress or swipe down for QS
-        when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(true);
-        when(mLockscreenShadeTransitionController.getFractionToShade()).thenReturn(1f);
-
-        // WHEN ACTION_MOVE is received and touch is within sensor
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
-
-        // THEN the touch is NOT processed
-        verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
-                anyBoolean());
-    }
-
-
-    @Test
-    public void onTouch_qsDrag_processesTouchWhenAlternateBouncerVisible()
-            throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
-
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        // GIVEN swipe down for QS
-        when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(false);
-        when(mLockscreenShadeTransitionController.getQSDragProgress()).thenReturn(1f);
-
-        // WHEN ACTION_MOVE is received and touch is within sensor
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                touchProcessorResult.first);
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
-
-        // THEN the touch is still processed
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
-                anyBoolean());
-    }
-
-    @Test
-    public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
-        // GIVEN UDFPS overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        // GIVEN there's been an AoD interrupt
-        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
-        mScreenObserver.onScreenTurnedOn();
-        mUdfpsController.onAodInterrupt(0, 0, 0, 0);
-
-        // THEN finger is considered down
-        assertTrue(mUdfpsController.isFingerDown());
-
-        // WHEN udfps receives an ACQUIRED_GOOD after the display is configured
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
-        verify(mFingerprintManager).setUdfpsOverlayController(
-                mUdfpsOverlayControllerCaptor.capture());
-        mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_GOOD);
-        mFgExecutor.runAllReady();
-
-        // THEN is fingerDown should be FALSE
-        assertFalse(mUdfpsController.isFingerDown());
-    }
-
-    @Test
-    public void playHaptic_onAodInterrupt_onAcquiredBad_performHapticFeedback()
-            throws RemoteException {
-        // GIVEN UDFPS overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        // GIVEN there's been an AoD interrupt
-        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
-        mScreenObserver.onScreenTurnedOn();
-        mUdfpsController.onAodInterrupt(0, 0, 0, 0);
-
-        // THEN vibrate is used
-        verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
-    }
-
-    @Test
-    public void onAcquiredCalbacks() {
-        runWithAllParams(
-                this::ultrasonicCallbackOnAcquired);
-    }
-
-    public void ultrasonicCallbackOnAcquired(TestParams testParams) throws RemoteException{
-        if (testParams.sensorProps.sensorType
-                == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC) {
-            reset(mUdfpsView);
-
-            UdfpsController.Callback callbackMock = mock(UdfpsController.Callback.class);
-            mUdfpsController.addCallback(callbackMock);
-
-            // GIVEN UDFPS overlay is showing
-            mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                    BiometricRequestConstants.REASON_AUTH_KEYGUARD,
-                    mUdfpsOverlayControllerCallback);
-            mFgExecutor.runAllReady();
-
-            verify(mFingerprintManager).setUdfpsOverlayController(
-                    mUdfpsOverlayControllerCaptor.capture());
-            mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_START);
-            mFgExecutor.runAllReady();
-
-            verify(callbackMock).onFingerDown();
-
-            mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_GOOD);
-            mFgExecutor.runAllReady();
-
-            verify(callbackMock).onFingerUp();
-        }
-    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
deleted file mode 100644
index 7986051..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Flags;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.animation.ActivityTransitionAnimator;
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeExpansionChangeEvent;
-import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-
-import org.junit.Before;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class UdfpsKeyguardViewLegacyControllerBaseTest extends SysuiTestCase {
-    // Dependencies
-    protected @Mock UdfpsKeyguardViewLegacy mView;
-    protected @Mock Context mResourceContext;
-    protected @Mock StatusBarStateController mStatusBarStateController;
-    protected @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
-    protected @Mock StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    protected @Mock LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    protected @Mock DumpManager mDumpManager;
-    protected @Mock DelayableExecutor mExecutor;
-    protected @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    protected @Mock KeyguardStateController mKeyguardStateController;
-    protected @Mock KeyguardViewMediator mKeyguardViewMediator;
-    protected @Mock ConfigurationController mConfigurationController;
-    protected @Mock UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
-    protected @Mock SystemUIDialogManager mDialogManager;
-    protected @Mock UdfpsController mUdfpsController;
-    protected @Mock ActivityTransitionAnimator mActivityTransitionAnimator;
-    protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
-    protected @Mock ShadeInteractor mShadeInteractor;
-    protected @Mock AlternateBouncerInteractor mAlternateBouncerInteractor;
-    protected @Mock UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
-    protected @Mock SelectedUserInteractor mSelectedUserInteractor;
-    protected @Mock KeyguardTransitionInteractor mKeyguardTransitionInteractor;
-    protected @Mock UdfpsOverlayInteractor mUdfpsOverlayInteractor;
-
-    protected FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
-
-    protected UdfpsKeyguardViewControllerLegacy mController;
-
-    // Capture listeners so that they can be used to send events
-    private @Captor ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
-    protected StatusBarStateController.StateListener mStatusBarStateListener;
-
-    private @Captor ArgumentCaptor<KeyguardStateController.Callback>
-            mKeyguardStateControllerCallbackCaptor;
-    protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
-
-    private @Captor ArgumentCaptor<StatusBarKeyguardViewManager.KeyguardViewManagerCallback>
-            mKeyguardViewManagerCallbackArgumentCaptor;
-    protected StatusBarKeyguardViewManager.KeyguardViewManagerCallback mKeyguardViewManagerCallback;
-
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
-        when(mView.getContext()).thenReturn(mResourceContext);
-        when(mResourceContext.getString(anyInt())).thenReturn("test string");
-        when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
-        when(mView.getUnpausedAlpha()).thenReturn(255);
-        when(mShadeExpansionStateManager.addExpansionListener(any())).thenReturn(
-                new ShadeExpansionChangeEvent(0, false, false));
-        mController = createUdfpsKeyguardViewController();
-    }
-
-    protected void sendStatusBarStateChanged(int statusBarState) {
-        mStatusBarStateListener.onStateChanged(statusBarState);
-    }
-
-    protected void captureStatusBarStateListeners() {
-        verify(mStatusBarStateController).addCallback(mStateListenerCaptor.capture());
-        mStatusBarStateListener = mStateListenerCaptor.getValue();
-    }
-
-    protected void captureKeyguardStateControllerCallback() {
-        verify(mKeyguardStateController).addCallback(
-                mKeyguardStateControllerCallbackCaptor.capture());
-        mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
-    }
-
-    public UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController() {
-        return createUdfpsKeyguardViewController(false);
-    }
-
-    public void captureKeyGuardViewManagerCallback() {
-        verify(mStatusBarKeyguardViewManager).addCallback(
-                mKeyguardViewManagerCallbackArgumentCaptor.capture());
-        mKeyguardViewManagerCallback = mKeyguardViewManagerCallbackArgumentCaptor.getValue();
-    }
-
-    protected UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController(
-            boolean useModernBouncer) {
-        UdfpsKeyguardViewControllerLegacy controller = new UdfpsKeyguardViewControllerLegacy(
-                mView,
-                mStatusBarStateController,
-                mStatusBarKeyguardViewManager,
-                mKeyguardUpdateMonitor,
-                mDumpManager,
-                mLockscreenShadeTransitionController,
-                mConfigurationController,
-                mKeyguardStateController,
-                mUnlockedScreenOffAnimationController,
-                mDialogManager,
-                mUdfpsController,
-                mActivityTransitionAnimator,
-                mPrimaryBouncerInteractor,
-                mAlternateBouncerInteractor,
-                mUdfpsKeyguardAccessibilityDelegate,
-                mSelectedUserInteractor,
-                mKeyguardTransitionInteractor,
-                mShadeInteractor,
-                mUdfpsOverlayInteractor);
-        return controller;
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
deleted file mode 100644
index 98d8b05..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.TestableLooper;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.statusbar.StatusBarState;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class UdfpsKeyguardViewLegacyControllerTest extends
-        UdfpsKeyguardViewLegacyControllerBaseTest {
-    @Override
-    public UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController() {
-        return createUdfpsKeyguardViewController(/* useModernBouncer */ false);
-    }
-
-    @Test
-    public void testShouldPauseAuth_bouncerShowing() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
-
-        when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
-        when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true);
-        when(mView.getUnpausedAlpha()).thenReturn(0);
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testRegistersStatusBarStateListenersOnAttached() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-    }
-
-    @Test
-    public void testViewControllerQueriesSBStateOnAttached() {
-        mController.onViewAttached();
-        verify(mStatusBarStateController).getState();
-
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
-        captureStatusBarStateListeners();
-
-        mController.onViewAttached();
-        verify(mView, atLeast(1)).setPauseAuth(true);
-    }
-
-    @Test
-    public void testListenersUnregisteredOnDetached() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-        captureKeyguardStateControllerCallback();
-        mController.onViewDetached();
-
-        verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
-        verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
-    }
-
-    @Test
-    public void testShouldPauseAuthUnpausedAlpha0() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        when(mView.getUnpausedAlpha()).thenReturn(0);
-        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
-
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testShouldNotPauseAuthOnKeyguard() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
-
-        assertFalse(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void onBiometricAuthenticated_pauseAuth() {
-        // GIVEN view is attached and we're on the keyguard (see testShouldNotPauseAuthOnKeyguard)
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
-
-        // WHEN biometric is authenticated
-        captureKeyguardStateControllerCallback();
-        when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
-        mKeyguardStateControllerCallback.onUnlockedChanged();
-
-        // THEN pause auth
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testShouldPauseAuthIsLaunchTransitionFadingAway() {
-        // GIVEN view is attached and we're on the keyguard (see testShouldNotPauseAuthOnKeyguard)
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
-
-        // WHEN isLaunchTransitionFadingAway=true
-        captureKeyguardStateControllerCallback();
-        when(mKeyguardStateController.isLaunchTransitionFadingAway()).thenReturn(true);
-        mKeyguardStateControllerCallback.onLaunchTransitionFadingAwayChanged();
-
-        // THEN pause auth
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testShouldPauseAuthOnShadeLocked() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
-
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testShouldPauseAuthOnShade() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        // WHEN not on keyguard yet (shade = home)
-        sendStatusBarStateChanged(StatusBarState.SHADE);
-
-        // THEN pause auth
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testShouldPauseAuthAnimatingScreenOffFromShade() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        // WHEN transitioning from home/shade => keyguard + animating screen off
-        mStatusBarStateListener.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD);
-        when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(true);
-
-        // THEN pause auth
-        assertTrue(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testDoNotPauseAuthAnimatingScreenOffFromLS() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        // WHEN animating screen off transition from LS => AOD
-        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
-        when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(true);
-
-        // THEN don't pause auth
-        assertFalse(mController.shouldPauseAuth());
-    }
-
-    @Test
-    public void testOverrideShouldPauseAuthOnShadeLocked() {
-        mController.onViewAttached();
-        captureStatusBarStateListeners();
-
-        sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
-        assertTrue(mController.shouldPauseAuth());
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
deleted file mode 100644
index 29a6e56..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * Copyright (C) 2022 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.biometrics
-
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF
-import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN
-import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
-import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
-import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
-import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionState
-import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-@TestableLooper.RunWithLooper
-@kotlinx.coroutines.ExperimentalCoroutinesApi
-class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
-    UdfpsKeyguardViewLegacyControllerBaseTest() {
-    private val kosmos = testKosmos()
-    private val testScope = kosmos.testScope
-
-    private val keyguardBouncerRepository = kosmos.fakeKeyguardBouncerRepository
-    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
-
-    @Before
-    override fun setUp() {
-        allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
-        MockitoAnnotations.initMocks(this)
-        super.setUp()
-    }
-
-    override fun createUdfpsKeyguardViewController(): UdfpsKeyguardViewControllerLegacy {
-        mPrimaryBouncerInteractor = kosmos.primaryBouncerInteractor
-        mAlternateBouncerInteractor = kosmos.alternateBouncerInteractor
-        mKeyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
-        mUdfpsOverlayInteractor = kosmos.udfpsOverlayInteractor
-        return createUdfpsKeyguardViewController(/* useModernBouncer */ true)
-    }
-
-    @Test
-    fun bouncerExpansionChange_fadeIn() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            captureKeyguardStateControllerCallback()
-            Mockito.reset(mView)
-
-            // WHEN status bar expansion is 0
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
-            runCurrent()
-
-            // THEN alpha is 0
-            verify(mView).unpausedAlpha = 0
-
-            job.cancel()
-        }
-
-    @Test
-    fun bouncerExpansionChange_pauseAuth() =
-        testScope.runTest {
-            // GIVEN view is attached + on the keyguard
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
-            Mockito.reset(mView)
-
-            // WHEN panelViewExpansion changes to hide
-            whenever(mView.unpausedAlpha).thenReturn(0)
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
-            runCurrent()
-
-            // THEN pause auth is updated to PAUSE
-            verify(mView, Mockito.atLeastOnce()).setPauseAuth(true)
-
-            job.cancel()
-        }
-
-    @Test
-    fun bouncerExpansionChange_unpauseAuth() =
-        testScope.runTest {
-            // GIVEN view is attached + on the keyguard + panel expansion is 0f
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
-            Mockito.reset(mView)
-
-            // WHEN panelViewExpansion changes to expanded
-            whenever(mView.unpausedAlpha).thenReturn(255)
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_HIDDEN)
-            runCurrent()
-
-            // THEN pause auth is updated to NOT pause
-            verify(mView, Mockito.atLeastOnce()).setPauseAuth(false)
-
-            job.cancel()
-        }
-
-    @Test
-    fun shadeLocked_showAlternateBouncer_unpauseAuth() =
-        testScope.runTest {
-            // GIVEN view is attached + on the SHADE_LOCKED (udfps view not showing)
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED)
-
-            // WHEN alternate bouncer is requested
-            val job = mController.listenForAlternateBouncerVisibility(this)
-            keyguardBouncerRepository.setAlternateVisible(true)
-            runCurrent()
-
-            // THEN udfps view will animate in & pause auth is updated to NOT pause
-            verify(mView).animateInUdfpsBouncer(any())
-            assertFalse(mController.shouldPauseAuth())
-
-            job.cancel()
-        }
-
-    /** After migration to MODERN_BOUNCER, replaces UdfpsKeyguardViewControllerTest version */
-    @Test
-    fun shouldPauseAuthBouncerShowing() =
-        testScope.runTest {
-            // GIVEN view attached and we're on the keyguard
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
-
-            // WHEN the bouncer expansion is VISIBLE
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
-            runCurrent()
-
-            // THEN UDFPS shouldPauseAuth == true
-            assertTrue(mController.shouldPauseAuth())
-
-            job.cancel()
-        }
-
-    @Test
-    fun shouldHandleTouchesChange() =
-        testScope.runTest {
-            val shouldHandleTouches by collectLastValue(mUdfpsOverlayInteractor.shouldHandleTouches)
-
-            // GIVEN view is attached + on the keyguard
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
-            whenever(mView.setPauseAuth(true)).thenReturn(true)
-            whenever(mView.unpausedAlpha).thenReturn(0)
-
-            // WHEN panelViewExpansion changes to expanded
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
-            runCurrent()
-
-            // THEN UDFPS auth is paused and should not handle touches
-            assertThat(mController.shouldPauseAuth()).isTrue()
-            assertThat(shouldHandleTouches!!).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun shouldHandleTouchesOnDetach() =
-        testScope.runTest {
-            val shouldHandleTouches by collectLastValue(mUdfpsOverlayInteractor.shouldHandleTouches)
-
-            // GIVEN view is attached + on the keyguard
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
-            whenever(mView.setPauseAuth(true)).thenReturn(true)
-            whenever(mView.unpausedAlpha).thenReturn(0)
-
-            // WHEN panelViewExpansion changes to expanded
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
-            runCurrent()
-
-            mController.onViewDetached()
-
-            // THEN UDFPS auth is paused and should not handle touches
-            assertThat(mController.shouldPauseAuth()).isTrue()
-            assertThat(shouldHandleTouches!!).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun fadeFromDialogSuggestedAlpha() =
-        testScope.runTest {
-            // GIVEN view is attached and status bar expansion is 1f
-            mController.onViewAttached()
-            captureStatusBarStateListeners()
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_HIDDEN)
-            runCurrent()
-            Mockito.reset(mView)
-
-            // WHEN dialog suggested alpha is .6f
-            whenever(mView.dialogSuggestedAlpha).thenReturn(.6f)
-            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
-
-            // THEN alpha is updated based on dialog suggested alpha
-            verify(mView).unpausedAlpha = (.6f * 255).toInt()
-
-            job.cancel()
-        }
-
-    @Test
-    fun transitionToFullShadeProgress() =
-        testScope.runTest {
-            // GIVEN view is attached and status bar expansion is 1f
-            mController.onViewAttached()
-            val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryShow(true)
-            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_HIDDEN)
-            runCurrent()
-            Mockito.reset(mView)
-            whenever(mView.dialogSuggestedAlpha).thenReturn(1f)
-
-            // WHEN we're transitioning to the full shade
-            val transitionProgress = .6f
-            mController.setTransitionToFullShadeProgress(transitionProgress)
-
-            // THEN alpha is between 0 and 255
-            verify(mView).unpausedAlpha = ((1f - transitionProgress) * 255).toInt()
-
-            job.cancel()
-        }
-
-    @Test
-    fun aodToLockscreen_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForLockscreenAodTransitions(this)
-
-            // WHEN transitioning from lockscreen to aod
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(.3f),
-                    eq(.3f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN)
-                )
-
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(1f),
-                    eq(1f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN)
-                )
-
-            job.cancel()
-        }
-
-    @Test
-    fun lockscreenToAod_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForLockscreenAodTransitions(this)
-
-            // WHEN transitioning from lockscreen to aod
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(.3f),
-                    eq(.3f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN)
-                )
-
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(1f),
-                    eq(1f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN)
-                )
-
-            job.cancel()
-        }
-
-    @Test
-    fun goneToAod_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForGoneToAodTransition(this)
-
-            // WHEN transitioning from lockscreen to aod
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.GONE,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(.3f),
-                    eq(.3f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
-                )
-
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.GONE,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(1f),
-                    eq(1f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
-                )
-
-            job.cancel()
-        }
-
-    @Test
-    fun aodToOccluded_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForAodToOccludedTransitions(this)
-
-            // WHEN transitioning from aod to occluded
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.AOD,
-                    to = KeyguardState.OCCLUDED,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(eq(.7f), eq(.7f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE))
-
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.AOD,
-                    to = KeyguardState.OCCLUDED,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(eq(0f), eq(0f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE))
-
-            job.cancel()
-        }
-
-    @Test
-    fun occludedToAod_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForOccludedToAodTransition(this)
-
-            // WHEN transitioning from occluded to aod
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.OCCLUDED,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(.3f),
-                    eq(.3f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
-                )
-
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.OCCLUDED,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED
-                )
-            )
-            runCurrent()
-            // THEN doze amount is updated
-            verify(mView)
-                .onDozeAmountChanged(
-                    eq(1f),
-                    eq(1f),
-                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
-                )
-
-            job.cancel()
-        }
-
-    @Test
-    fun cancelledAodToLockscreen_dozeAmountChangedToZero() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            val job = mController.listenForLockscreenAodTransitions(this)
-            runCurrent()
-            Mockito.reset(mView)
-
-            // WHEN aod to lockscreen transition is cancelled
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.AOD,
-                    to = KeyguardState.LOCKSCREEN,
-                    value = 1f,
-                    transitionState = TransitionState.CANCELED
-                )
-            )
-            runCurrent()
-            // ... and WHEN the next transition is from lockscreen => occluded
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.OCCLUDED,
-                    value = .4f,
-                    transitionState = TransitionState.STARTED
-                )
-            )
-            runCurrent()
-
-            // THEN doze amount is updated to zero
-            verify(mView)
-                .onDozeAmountChanged(eq(0f), eq(0f), eq(ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN))
-            job.cancel()
-        }
-
-    @Test
-    fun cancelledLockscreenToAod_dozeAmountNotUpdatedToZero() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            val job = mController.listenForLockscreenAodTransitions(this)
-            runCurrent()
-            Mockito.reset(mView)
-
-            // WHEN lockscreen to aod transition is cancelled
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.CANCELED
-                )
-            )
-            runCurrent()
-
-            // THEN doze amount is NOT updated to zero
-            verify(mView, never()).onDozeAmountChanged(eq(0f), eq(0f), anyInt())
-            job.cancel()
-        }
-
-    @Test
-    fun dreamingToAod_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForDreamingToAodTransitions(this)
-            // WHEN dreaming to aod transition in progress
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.DREAMING,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-
-            // THEN doze amount is updated to
-            verify(mView).onDozeAmountChanged(eq(.3f), eq(.3f), eq(ANIMATE_APPEAR_ON_SCREEN_OFF))
-            job.cancel()
-        }
-
-    @Test
-    fun alternateBouncerToAod_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForAlternateBouncerToAodTransitions(this)
-            // WHEN alternate bouncer to aod transition in progress
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.ALTERNATE_BOUNCER,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-
-            // THEN doze amount is updated to
-            verify(mView)
-                .onDozeAmountChanged(eq(.3f), eq(.3f), eq(ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN))
-            job.cancel()
-        }
-
-    @Test
-    fun bouncerToAod_dozeAmountChanged() =
-        testScope.runTest {
-            // GIVEN view is attached
-            mController.onViewAttached()
-            Mockito.reset(mView)
-
-            val job = mController.listenForPrimaryBouncerToAodTransitions(this)
-            // WHEN alternate bouncer to aod transition in progress
-            transitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.PRIMARY_BOUNCER,
-                    to = KeyguardState.AOD,
-                    value = .3f,
-                    transitionState = TransitionState.RUNNING
-                )
-            )
-            runCurrent()
-
-            // THEN doze amount is updated to
-            verify(mView).onDozeAmountChanged(eq(.3f), eq(.3f), eq(ANIMATE_APPEAR_ON_SCREEN_OFF))
-            job.cancel()
-        }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 68cfa28..82ff617 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -16,12 +16,9 @@
 
 package com.android.systemui.bouncer.domain.interactor
 
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.keyguardUpdateMonitor
-import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.authentication.domain.interactor.authenticationInteractor
@@ -61,12 +58,6 @@
         underTest = kosmos.alternateBouncerInteractor
     }
 
-    @Test(expected = IllegalStateException::class)
-    @EnableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    fun enableUdfpsRefactor_deprecatedShowMethod_throwsIllegalStateException() {
-        underTest.show()
-    }
-
     @Test
     @DisableSceneContainer
     fun canShowAlternateBouncer_false_dueToTransitionState() =
@@ -101,21 +92,6 @@
         }
 
     @Test
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    fun canShowAlternateBouncerForFingerprint_givenCanShow() {
-        givenCanShowAlternateBouncer()
-        assertTrue(underTest.canShowAlternateBouncerForFingerprint())
-    }
-
-    @Test
-    fun canShowAlternateBouncerForFingerprint_alternateBouncerUIUnavailable() {
-        givenCanShowAlternateBouncer()
-        kosmos.keyguardBouncerRepository.setAlternateBouncerUIAvailable(false)
-
-        assertFalse(underTest.canShowAlternateBouncerForFingerprint())
-    }
-
-    @Test
     fun canShowAlternateBouncerForFingerprint_ifFingerprintIsNotUsuallyAllowed() {
         givenCanShowAlternateBouncer()
         kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
@@ -140,15 +116,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    fun show_whenCanShow() {
-        givenCanShowAlternateBouncer()
-
-        assertTrue(underTest.show())
-        assertTrue(kosmos.keyguardBouncerRepository.alternateBouncerVisible.value)
-    }
-
-    @Test
     fun canShowAlternateBouncerForFingerprint_butCanDismissLockScreen() {
         givenCanShowAlternateBouncer()
         whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(true)
@@ -165,15 +132,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    fun show_whenCannotShow() {
-        givenCannotShowAlternateBouncer()
-
-        assertFalse(underTest.show())
-        assertFalse(kosmos.keyguardBouncerRepository.alternateBouncerVisible.value)
-    }
-
-    @Test
     fun hide_wasPreviouslyShowing() {
         kosmos.keyguardBouncerRepository.setAlternateVisible(true)
 
@@ -190,7 +148,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
     fun canShowAlternateBouncerForFingerprint_rearFps() {
         givenCanShowAlternateBouncer()
         kosmos.fingerprintPropertyRepository.supportsRearFps() // does not support alternate bouncer
@@ -198,29 +155,6 @@
         assertFalse(underTest.canShowAlternateBouncerForFingerprint())
     }
 
-    @Test
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    fun alternateBouncerUiAvailable_fromMultipleSources() {
-        assertFalse(kosmos.keyguardBouncerRepository.alternateBouncerUIAvailable.value)
-
-        // GIVEN there are two different sources indicating the alternate bouncer is available
-        underTest.setAlternateBouncerUIAvailable(true, "source1")
-        underTest.setAlternateBouncerUIAvailable(true, "source2")
-        assertTrue(kosmos.keyguardBouncerRepository.alternateBouncerUIAvailable.value)
-
-        // WHEN one of the sources no longer says the UI is available
-        underTest.setAlternateBouncerUIAvailable(false, "source1")
-
-        // THEN alternate bouncer UI is still available (from the other source)
-        assertTrue(kosmos.keyguardBouncerRepository.alternateBouncerUIAvailable.value)
-
-        // WHEN all sources say the UI is not available
-        underTest.setAlternateBouncerUIAvailable(false, "source2")
-
-        // THEN alternate boucer UI is not available
-        assertFalse(kosmos.keyguardBouncerRepository.alternateBouncerUIAvailable.value)
-    }
-
     private fun givenAlternateBouncerSupported() {
         kosmos.givenAlternateBouncerSupported()
     }
@@ -228,8 +162,4 @@
     private fun givenCanShowAlternateBouncer() {
         kosmos.givenCanShowAlternateBouncer()
     }
-
-    private fun givenCannotShowAlternateBouncer() {
-        kosmos.givenCannotShowAlternateBouncer()
-    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index ee65fbd..1e86516 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.communal
 
+import android.os.UserHandle
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.provider.Settings
@@ -77,7 +78,11 @@
     @Before
     fun setUp() {
         with(kosmos) {
-            fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT)
+            fakeSettings.putIntForUser(
+                Settings.System.SCREEN_OFF_TIMEOUT,
+                SCREEN_TIMEOUT,
+                UserHandle.USER_CURRENT,
+            )
             kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
 
             underTest =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 6c6de61..cd8b2e1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -440,6 +440,28 @@
         }
 
     @Test
+    fun displayAdditionEvent_emptyByDefault() =
+        testScope.runTest {
+            setDisplays(1, 2, 3)
+
+            val lastAddedDisplay by lastDisplayAdditionEvent()
+
+            assertThat(lastAddedDisplay).isNull()
+        }
+
+    @Test
+    fun displayAdditionEvent_displaysAdded_doesNotReplayEventsToNewSubscribers() =
+        testScope.runTest {
+            val priorDisplayAdded by lastDisplayAdditionEvent()
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+            assertThat(priorDisplayAdded?.displayId).isEqualTo(1)
+
+            val lastAddedDisplay by collectLastValue(displayRepository.displayAdditionEvent)
+            assertThat(lastAddedDisplay).isNull()
+        }
+
+    @Test
     fun defaultDisplayOff_changes() =
         testScope.runTest {
             val defaultDisplayOff by latestDefaultDisplayOffFlowValue()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
index 2a2a82d..b5ea305 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -39,7 +39,6 @@
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.FakeTrustRepository
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
@@ -100,18 +99,14 @@
                 FakeTrustRepository(),
                 testScope.backgroundScope,
                 mSelectedUserInteractor,
-                faceAuthInteractor
+                faceAuthInteractor,
             )
 
         alternateBouncerInteractor =
             AlternateBouncerInteractor(
-                mock(StatusBarStateController::class.java),
-                mock(KeyguardStateController::class.java),
                 bouncerRepository,
                 FakeFingerprintPropertyRepository(),
-                biometricSettingsRepository,
                 FakeSystemClock(),
-                keyguardUpdateMonitor,
                 { mock(DeviceEntryBiometricsAllowedInteractor::class.java) },
                 { mock(KeyguardInteractor::class.java) },
                 { mock(KeyguardTransitionInteractor::class.java) },
@@ -121,13 +116,12 @@
 
         underTest =
             DeviceEntrySideFpsOverlayInteractor(
-                testScope.backgroundScope,
                 mContext,
                 deviceEntryFingerprintAuthRepository,
                 kosmos.sceneInteractor,
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
-                keyguardUpdateMonitor
+                keyguardUpdateMonitor,
             )
     }
 
@@ -142,7 +136,7 @@
                 isShowing = true,
                 isAnimatingAway = false,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isTrue()
         }
@@ -158,7 +152,7 @@
                 isShowing = false,
                 isAnimatingAway = false,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -169,13 +163,12 @@
         testScope.runTest {
             underTest =
                 DeviceEntrySideFpsOverlayInteractor(
-                    testScope.backgroundScope,
                     mContext,
                     deviceEntryFingerprintAuthRepository,
                     kosmos.sceneInteractor,
                     primaryBouncerInteractor,
                     alternateBouncerInteractor,
-                    keyguardUpdateMonitor
+                    keyguardUpdateMonitor,
                 )
 
             val showIndicatorForDeviceEntry by
@@ -185,7 +178,7 @@
             updateBouncerScene(
                 isActive = true,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isTrue()
         }
@@ -196,13 +189,12 @@
         testScope.runTest {
             underTest =
                 DeviceEntrySideFpsOverlayInteractor(
-                    testScope.backgroundScope,
                     mContext,
                     deviceEntryFingerprintAuthRepository,
                     kosmos.sceneInteractor,
                     primaryBouncerInteractor,
                     alternateBouncerInteractor,
-                    keyguardUpdateMonitor
+                    keyguardUpdateMonitor,
                 )
 
             val showIndicatorForDeviceEntry by
@@ -212,7 +204,7 @@
             updateBouncerScene(
                 isActive = false,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -228,7 +220,7 @@
                 isShowing = true,
                 isAnimatingAway = false,
                 fpsDetectionRunning = false,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -245,7 +237,7 @@
                 isShowing = true,
                 isAnimatingAway = false,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = false
+                isUnlockingWithFpAllowed = false,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -261,7 +253,7 @@
             updateBouncerScene(
                 isActive = true,
                 fpsDetectionRunning = false,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -277,7 +269,7 @@
             updateBouncerScene(
                 isActive = true,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = false
+                isUnlockingWithFpAllowed = false,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -294,7 +286,7 @@
                 isShowing = true,
                 isAnimatingAway = true,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
             assertThat(showIndicatorForDeviceEntry).isFalse()
         }
@@ -325,7 +317,7 @@
                 isShowing = true,
                 isAnimatingAway = false,
                 fpsDetectionRunning = true,
-                isUnlockingWithFpAllowed = true
+                isUnlockingWithFpAllowed = true,
             )
 
             // Another request to show indicator for deviceEntryFingerprintAuthRepository update
@@ -355,7 +347,7 @@
             .thenReturn(isUnlockingWithFpAllowed)
         mContext.orCreateTestableResources.addOverride(
             R.bool.config_show_sidefps_hint_on_bouncer,
-            true
+            true,
         )
     }
 
@@ -366,7 +358,7 @@
     ) {
         kosmos.sceneInteractor.changeScene(
             if (isActive) Scenes.Bouncer else Scenes.Lockscreen,
-            "reason"
+            "reason",
         )
 
         whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
@@ -375,7 +367,7 @@
             .thenReturn(isUnlockingWithFpAllowed)
         mContext.orCreateTestableResources.addOverride(
             R.bool.config_show_sidefps_hint_on_bouncer,
-            true
+            true,
         )
         runCurrent()
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
index c4eabd8..3800608 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper
 import android.view.View
 import android.view.layoutInflater
@@ -24,7 +23,6 @@
 import android.view.windowManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.domain.interactor.givenCanShowAlternateBouncer
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -63,7 +61,7 @@
                 kosmos.mockedLayoutInflater.inflate(
                     eq(R.layout.alternate_bouncer),
                     isNull(),
-                    anyBoolean()
+                    anyBoolean(),
                 )
             )
             .thenReturn(mockedAltBouncerView)
@@ -71,7 +69,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
     fun addViewToWindowManager() {
         testScope.runTest {
             kosmos.givenCanShowAlternateBouncer()
@@ -85,7 +82,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
     fun viewRemovedImmediatelyIfAlreadyAttachedToWindow() {
         testScope.runTest {
             kosmos.givenCanShowAlternateBouncer()
@@ -107,7 +103,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
     fun viewNotRemovedUntilAttachedToWindow() {
         testScope.runTest {
             kosmos.givenCanShowAlternateBouncer()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
index 1c99eff..d94c97a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
@@ -28,12 +28,12 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
-import com.android.systemui.res.R
 import com.android.systemui.shared.R as sharedR
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
 import com.android.systemui.util.mockito.any
@@ -135,7 +135,7 @@
         assertThat(smartspaceConstraints.layout.topToBottom).isEqualTo(dateView.id)
 
         val dateConstraints = constraintSet.getConstraint(dateView.id)
-        assertThat(dateConstraints.layout.topToBottom).isEqualTo(R.id.lockscreen_clock_view)
+        assertThat(dateConstraints.layout.topToBottom).isEqualTo(customR.id.lockscreen_clock_view)
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
index c1bd378..5d95480 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
@@ -19,7 +19,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
 import com.android.systemui.coroutines.collectLastValue
@@ -34,7 +33,6 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @ExperimentalCoroutinesApi
 @RunWith(AndroidJUnit4::class)
@@ -49,7 +47,6 @@
     @Test
     fun alternateBouncerTransition_alternateBouncerWindowRequiredTrue() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
             val alternateBouncerWindowRequired by
                 collectLastValue(underTest.alternateBouncerWindowRequired)
             fingerprintPropertyRepository.supportsUdfps()
@@ -64,28 +61,7 @@
             assertThat(alternateBouncerWindowRequired).isTrue()
 
             transitionRepository.sendTransitionSteps(
-                listOf(
-                    stepFromAlternateBouncer(1.0f, TransitionState.FINISHED),
-                ),
-                testScope,
-            )
-            assertThat(alternateBouncerWindowRequired).isFalse()
-        }
-
-    @Test
-    fun deviceEntryUdfpsFlagDisabled_alternateBouncerWindowRequiredFalse() =
-        testScope.runTest {
-            mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-            val alternateBouncerWindowRequired by
-                collectLastValue(underTest.alternateBouncerWindowRequired)
-            fingerprintPropertyRepository.supportsUdfps()
-            transitionRepository.sendTransitionSteps(
-                listOf(
-                    stepFromAlternateBouncer(0f, TransitionState.STARTED),
-                    stepFromAlternateBouncer(.4f),
-                    stepFromAlternateBouncer(.6f),
-                    stepFromAlternateBouncer(1f),
-                ),
+                listOf(stepFromAlternateBouncer(1.0f, TransitionState.FINISHED)),
                 testScope,
             )
             assertThat(alternateBouncerWindowRequired).isFalse()
@@ -94,7 +70,6 @@
     @Test
     fun lockscreenTransition_alternateBouncerWindowRequiredFalse() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
             val alternateBouncerWindowRequired by
                 collectLastValue(underTest.alternateBouncerWindowRequired)
             fingerprintPropertyRepository.supportsUdfps()
@@ -113,7 +88,6 @@
     @Test
     fun rearFps_alternateBouncerWindowRequiredFalse() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
             val alternateBouncerWindowRequired by
                 collectLastValue(underTest.alternateBouncerWindowRequired)
             fingerprintPropertyRepository.supportsRearFps()
@@ -131,7 +105,7 @@
 
     private fun stepFromAlternateBouncer(
         value: Float,
-        state: TransitionState = TransitionState.RUNNING
+        state: TransitionState = TransitionState.RUNNING,
     ): TransitionStep {
         return step(
             from = KeyguardState.ALTERNATE_BOUNCER,
@@ -143,7 +117,7 @@
 
     private fun stepFromDozingToLockscreen(
         value: Float,
-        state: TransitionState = TransitionState.RUNNING
+        state: TransitionState = TransitionState.RUNNING,
     ): TransitionStep {
         return step(
             from = KeyguardState.DOZING,
@@ -157,14 +131,14 @@
         from: KeyguardState,
         to: KeyguardState,
         value: Float,
-        transitionState: TransitionState
+        transitionState: TransitionState,
     ): TransitionStep {
         return TransitionStep(
             from = from,
             to = to,
             value = value,
             transitionState = transitionState,
-            ownerName = "AlternateBouncerViewModelTest"
+            ownerName = "AlternateBouncerViewModelTest",
         )
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepositoryTest.kt
index 14d6094..e5bdc2e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepositoryTest.kt
@@ -54,7 +54,7 @@
     private fun setRowsInConfig(rows: Int) =
         with(kosmos) {
             testCase.context.orCreateTestableResources.addOverride(
-                R.integer.quick_settings_max_rows,
+                R.integer.quick_settings_paginated_grid_num_rows,
                 rows,
             )
             fakeConfigurationRepository.onConfigurationChange()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepositoryTest.kt
index ae6f576..cda3d48 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepositoryTest.kt
@@ -54,7 +54,7 @@
     private fun setRowsInConfig(rows: Int) =
         with(kosmos) {
             testCase.context.orCreateTestableResources.addOverride(
-                R.integer.quick_qs_panel_max_rows,
+                R.integer.quick_qs_paginated_grid_num_rows,
                 rows,
             )
             fakeConfigurationRepository.onConfigurationChange()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
index a1c0ef2..2c894f9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
@@ -151,7 +151,7 @@
 
     private fun Kosmos.setRows(rows: Int) {
         testCase.context.orCreateTestableResources.addOverride(
-            R.integer.quick_qs_panel_max_rows,
+            R.integer.quick_qs_paginated_grid_num_rows,
             rows,
         )
         fakeConfigurationRepository.onConfigurationChange()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 3f550ca..0d5ddae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -18,9 +18,12 @@
 
 import static com.android.systemui.screenrecord.RecordingService.GROUP_KEY_ERROR_SAVING;
 import static com.android.systemui.screenrecord.RecordingService.GROUP_KEY_SAVED;
+import static com.android.systemui.screenrecord.RecordingService.NOTIF_GROUP_ID_ERROR_SAVING;
+import static com.android.systemui.screenrecord.RecordingService.NOTIF_GROUP_ID_SAVED;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -235,7 +238,9 @@
 
         // Processing notification
         ArgumentCaptor<Notification> notifCaptor = ArgumentCaptor.forClass(Notification.class);
-        verify(mNotificationManager).notifyAsUser(any(), anyInt(), notifCaptor.capture(), any());
+        ArgumentCaptor<Integer> notifIdCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mNotificationManager)
+                .notifyAsUser(any(), notifIdCaptor.capture(), notifCaptor.capture(), any());
         assertEquals(GROUP_KEY_SAVED, notifCaptor.getValue().getGroup());
 
         reset(mNotificationManager);
@@ -243,7 +248,7 @@
         mRunnableCaptor.getValue().run();
 
         verify(mNotificationManager, times(2))
-                .notifyAsUser(any(), anyInt(), notifCaptor.capture(), any());
+                .notifyAsUser(any(), notifIdCaptor.capture(), notifCaptor.capture(), any());
         // Saved notification
         Notification saveNotification = notifCaptor.getAllValues().get(0);
         assertFalse(saveNotification.isGroupSummary());
@@ -252,6 +257,10 @@
         Notification groupSummaryNotification = notifCaptor.getAllValues().get(1);
         assertTrue(groupSummaryNotification.isGroupSummary());
         assertEquals(GROUP_KEY_SAVED, groupSummaryNotification.getGroup());
+
+        // Verify the group notification ID and the individual notification ID are different
+        assertNotEquals(NOTIF_GROUP_ID_SAVED, (int) notifIdCaptor.getAllValues().get(0));
+        assertEquals(NOTIF_GROUP_ID_SAVED, (int) notifIdCaptor.getAllValues().get(1));
     }
 
     @Test
@@ -264,9 +273,12 @@
 
         verify(mRecordingService).createErrorSavingNotification(any());
         ArgumentCaptor<Notification> notifCaptor = ArgumentCaptor.forClass(Notification.class);
-        verify(mNotificationManager).notifyAsUser(any(), anyInt(), notifCaptor.capture(), any());
+        ArgumentCaptor<Integer> notifIdCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mNotificationManager)
+                .notifyAsUser(any(), notifIdCaptor.capture(), notifCaptor.capture(), any());
         assertTrue(notifCaptor.getValue().isGroupSummary());
         assertEquals(GROUP_KEY_ERROR_SAVING, notifCaptor.getValue().getGroup());
+        assertEquals(NOTIF_GROUP_ID_ERROR_SAVING, (int) notifIdCaptor.getValue());
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 0454317..06d19d7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -68,13 +68,13 @@
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.EmptyLockIconViewController;
 import com.android.keyguard.KeyguardClockSwitch;
 import com.android.keyguard.KeyguardClockSwitchController;
 import com.android.keyguard.KeyguardSliceViewController;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LegacyLockIconViewController;
 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -271,6 +271,7 @@
     @Mock protected KeyguardUserSwitcherController mKeyguardUserSwitcherController;
     @Mock protected KeyguardStatusViewComponent mKeyguardStatusViewComponent;
     @Mock protected KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
+    @Mock protected EmptyLockIconViewController mLockIconViewController;
     @Mock protected KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
     @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController;
     @Mock protected KeyguardStatusBarViewController mKeyguardStatusBarViewController;
@@ -285,7 +286,6 @@
     @Mock protected AmbientState mAmbientState;
     @Mock protected UserManager mUserManager;
     @Mock protected UiEventLogger mUiEventLogger;
-    @Mock protected LegacyLockIconViewController mLockIconViewController;
     @Mock protected KeyguardViewConfigurator mKeyguardViewConfigurator;
     @Mock protected KeyguardRootView mKeyguardRootView;
     @Mock protected View mKeyguardRootViewChild;
@@ -397,7 +397,6 @@
         mFeatureFlags.set(Flags.QS_USER_DETAIL_SHORTCUT, false);
 
         mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR);
-        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
 
         mMainDispatcher = getMainDispatcher();
         KeyguardInteractorFactory.WithDependencies keyguardInteractorDeps =
@@ -687,6 +686,9 @@
         when(longPressHandlingView.getResources()).thenReturn(longPressHandlingViewRes);
         when(longPressHandlingViewRes.getString(anyInt())).thenReturn("");
 
+        when(mKeyguardRootView.findViewById(anyInt())).thenReturn(mKeyguardRootViewChild);
+        when(mKeyguardViewConfigurator.getKeyguardRootView()).thenReturn(mKeyguardRootView);
+
         mNotificationPanelViewController = new NotificationPanelViewController(
                 mView,
                 mMainHandler,
@@ -852,7 +854,7 @@
             mNotificationPanelViewController.mBottomAreaShadeAlphaAnimator.cancel();
             mNotificationPanelViewController.cancelHeightAnimator();
             leakedAnimators = mNotificationPanelViewController.mTestSetOfAnimatorsUsed.stream()
-                    .filter(Animator::isRunning).toList();
+                .filter(Animator::isRunning).toList();
             mNotificationPanelViewController.mTestSetOfAnimatorsUsed.forEach(Animator::cancel);
         }
         if (mMainHandler != null) {
@@ -869,11 +871,7 @@
         when(mNotificationStackScrollLayoutController.getTop()).thenReturn(0);
         when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(stackBottom);
         when(mNotificationStackScrollLayoutController.getBottom()).thenReturn(stackBottom);
-        when(mLockIconViewController.getTop()).thenReturn((float) (stackBottom - lockIconPadding));
-
         when(mKeyguardRootViewChild.getTop()).thenReturn((int) (stackBottom - lockIconPadding));
-        when(mKeyguardRootView.findViewById(anyInt())).thenReturn(mKeyguardRootViewChild);
-        when(mKeyguardViewConfigurator.getKeyguardRootView()).thenReturn(mKeyguardRootView);
 
         when(mResources.getDimensionPixelSize(R.dimen.keyguard_indication_bottom_padding))
                 .thenReturn(indicationPadding);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 43dbb40..ec75972 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -217,7 +217,6 @@
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(5);
 
-        mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(5);
     }
@@ -235,7 +234,6 @@
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(0);
 
-        mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(0);
     }
@@ -253,7 +251,6 @@
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(0);
 
-        mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(0);
     }
@@ -271,7 +268,6 @@
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(2);
 
-        mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(2);
     }
@@ -289,7 +285,6 @@
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(0);
 
-        mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
                 .isEqualTo(0);
     }
@@ -389,7 +384,6 @@
     @Test
     @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
     public void alternateBouncerVisible_onTouchEvent_notHandled() {
-        mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
         // GIVEN alternate bouncer is visible
         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 6f2302a..9fe5299 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -30,7 +30,6 @@
 import android.view.ViewTreeObserver
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityContainerController
-import com.android.keyguard.LegacyLockIconViewController
 import com.android.keyguard.dagger.KeyguardBouncerComponent
 import com.android.systemui.Flags
 import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
@@ -54,7 +53,6 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.res.R
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.statusbar.DragDownHelper
@@ -71,7 +69,6 @@
 import com.android.systemui.statusbar.phone.DozeScrimController
 import com.android.systemui.statusbar.phone.DozeServiceHost
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
@@ -80,6 +77,7 @@
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.emptyFlow
@@ -98,11 +96,10 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
-import java.util.Optional
-import org.mockito.Mockito.`when` as whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -125,12 +122,10 @@
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var ambientState: AmbientState
     @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
-    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
     @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
     @Mock private lateinit var quickSettingsController: QuickSettingsControllerImpl
     @Mock
     private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
-    @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
     @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
     @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
     @Mock
@@ -144,7 +139,7 @@
     @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
     @Mock
     private lateinit var unfoldTransitionProgressProvider:
-            Optional<UnfoldTransitionProgressProvider>
+        Optional<UnfoldTransitionProgressProvider>
     @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
     @Mock lateinit var dragDownHelper: DragDownHelper
     @Mock lateinit var mSelectedUserInteractor: SelectedUserInteractor
@@ -176,20 +171,17 @@
         MockitoAnnotations.initMocks(this)
         whenever(view.bottom).thenReturn(VIEW_BOTTOM)
         whenever(view.findViewById<ViewGroup>(R.id.keyguard_bouncer_container))
-                .thenReturn(mock(ViewGroup::class.java))
+            .thenReturn(mock(ViewGroup::class.java))
         whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
-                .thenReturn(keyguardBouncerComponent)
+            .thenReturn(keyguardBouncerComponent)
         whenever(keyguardBouncerComponent.securityContainerController)
-                .thenReturn(keyguardSecurityContainerController)
+            .thenReturn(keyguardSecurityContainerController)
         whenever(keyguardTransitionInteractor.transition(Edge.create(LOCKSCREEN, DREAMING)))
-                .thenReturn(emptyFlow<TransitionStep>())
+            .thenReturn(emptyFlow<TransitionStep>())
 
         featureFlagsClassic = FakeFeatureFlagsClassic()
         featureFlagsClassic.set(SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
         featureFlagsClassic.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
-        if (!SceneContainerFlag.isEnabled) {
-            mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-        }
         mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES)
 
         testScope = TestScope()
@@ -208,9 +200,7 @@
                 panelExpansionInteractor,
                 ShadeExpansionStateManager(),
                 stackScrollLayoutController,
-                statusBarKeyguardViewManager,
                 statusBarWindowStateController,
-                lockIconViewController,
                 centralSurfaces,
                 dozeServiceHost,
                 dozeScrimController,
@@ -233,7 +223,7 @@
                 quickSettingsController,
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
-                mock(BouncerViewBinder::class.java)
+                mock(BouncerViewBinder::class.java),
             )
         underTest.setupExpandedStatusBar()
         underTest.setDragDownHelper(dragDownHelper)
@@ -294,7 +284,7 @@
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
             whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
-                    .thenReturn(true)
+                .thenReturn(true)
             whenever(phoneStatusBarViewController.sendTouchToView(DOWN_EVENT)).thenReturn(true)
 
             val returnVal = interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
@@ -309,7 +299,7 @@
             underTest.setStatusBarViewController(phoneStatusBarViewController)
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
-                    .thenReturn(true)
+                .thenReturn(true)
             // Item we're testing
             whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(false)
 
@@ -327,7 +317,7 @@
             whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             // Item we're testing
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
-                    .thenReturn(false)
+                .thenReturn(false)
 
             val returnVal = interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
 
@@ -341,7 +331,7 @@
             underTest.setStatusBarViewController(phoneStatusBarViewController)
             whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
-                    .thenReturn(true)
+                .thenReturn(true)
             // Item we're testing
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(false)
 
@@ -358,7 +348,7 @@
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
             whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
-                    .thenReturn(true)
+                .thenReturn(true)
 
             // Down event first
             interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
@@ -379,7 +369,7 @@
             // GIVEN touch dispatcher in a state that returns true
             underTest.setStatusBarViewController(phoneStatusBarViewController)
             whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
-                    .thenReturn(true)
+                .thenReturn(true)
             assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
 
             // WHEN launch animation is running for 2 seconds
@@ -432,47 +422,13 @@
     }
 
     @Test
-    fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() {
-        // down event should be intercepted by keyguardViewManager
-        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
-                .thenReturn(true)
-
-        // Then touch should not be intercepted
-        val shouldIntercept = interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)
-        assertThat(shouldIntercept).isTrue()
-    }
-
-    @Test
-    @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
-    fun shouldInterceptTouchEvent_dozing_touchInLockIconArea_touchNotIntercepted() {
-        // GIVEN dozing
-        whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)
-        // AND alternate bouncer doesn't want the touch
-        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
-                .thenReturn(false)
-        // AND quick settings controller doesn't want it
-        whenever(quickSettingsController.shouldQuickSettingsIntercept(any(), any(), any()))
-                .thenReturn(false)
-        // AND the lock icon wants the touch
-        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT)).thenReturn(true)
-
-        // THEN touch should NOT be intercepted by NotificationShade
-        assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isFalse()
-    }
-
-    @Test
     @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
     fun shouldInterceptTouchEvent_dozing_touchNotInLockIconArea_touchIntercepted() {
         // GIVEN dozing
         whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)
-        // AND alternate bouncer doesn't want the touch
-        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
-                .thenReturn(false)
-        // AND the lock icon does NOT want the touch
-        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT)).thenReturn(false)
         // AND quick settings controller doesn't want it
         whenever(quickSettingsController.shouldQuickSettingsIntercept(any(), any(), any()))
-                .thenReturn(false)
+            .thenReturn(false)
 
         // THEN touch should be intercepted by NotificationShade
         assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isTrue()
@@ -483,14 +439,9 @@
     fun shouldInterceptTouchEvent_dozing_touchInStatusBar_touchIntercepted() {
         // GIVEN dozing
         whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)
-        // AND alternate bouncer doesn't want the touch
-        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
-                .thenReturn(false)
-        // AND the lock icon does NOT want the touch
-        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT)).thenReturn(false)
         // AND quick settings controller DOES want it
         whenever(quickSettingsController.shouldQuickSettingsIntercept(any(), any(), any()))
-                .thenReturn(true)
+            .thenReturn(true)
 
         // THEN touch should be intercepted by NotificationShade
         assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isTrue()
@@ -503,20 +454,13 @@
         whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)
         // AND pulsing
         whenever(dozeServiceHost.isPulsing()).thenReturn(true)
-        // AND status bar doesn't want it
-        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
-                .thenReturn(false)
-        // AND shade is not fully expanded (mock is false by default)
-        // AND the lock icon does NOT want the touch
-        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT)).thenReturn(false)
         // AND quick settings controller DOES want it
         whenever(quickSettingsController.shouldQuickSettingsIntercept(any(), any(), any()))
-                .thenReturn(true)
+            .thenReturn(true)
         // AND bouncer is not showing
         whenever(centralSurfaces.isBouncerShowing()).thenReturn(false)
         // AND panel view controller wants it
-        whenever(shadeViewController.handleExternalInterceptTouch(DOWN_EVENT))
-                .thenReturn(true)
+        whenever(shadeViewController.handleExternalInterceptTouch(DOWN_EVENT)).thenReturn(true)
 
         // THEN touch should be intercepted by NotificationShade
         assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isTrue()
@@ -589,12 +533,10 @@
         underTest.setupCommunalHubLayout()
 
         // Simluate attaching the view so flow collection starts.
-        val onAttachStateChangeListenerArgumentCaptor = ArgumentCaptor.forClass(
-            View.OnAttachStateChangeListener::class.java
-        )
-        verify(view, atLeast(1)).addOnAttachStateChangeListener(
-            onAttachStateChangeListenerArgumentCaptor.capture()
-        )
+        val onAttachStateChangeListenerArgumentCaptor =
+            ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
+        verify(view, atLeast(1))
+            .addOnAttachStateChangeListener(onAttachStateChangeListenerArgumentCaptor.capture())
         for (listener in onAttachStateChangeListenerArgumentCaptor.allValues) {
             listener.onViewAttachedToWindow(view)
         }
@@ -608,7 +550,7 @@
     @RequiresFlagsDisabled(Flags.FLAG_COMMUNAL_HUB)
     fun doesNotSetupCommunalHubLayout_whenFlagDisabled() {
         whenever(mGlanceableHubContainerController.communalAvailable())
-                .thenReturn(MutableStateFlow(false))
+            .thenReturn(MutableStateFlow(false))
 
         val mockCommunalPlaceholder = mock(View::class.java)
         val fakeViewIndex = 20
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index ca29dd9..9093b2b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -23,7 +23,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityContainerController
-import com.android.keyguard.LegacyLockIconViewController
 import com.android.keyguard.dagger.KeyguardBouncerComponent
 import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
@@ -57,7 +56,6 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.DozeScrimController
 import com.android.systemui.statusbar.phone.DozeServiceHost
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
@@ -104,11 +102,9 @@
     @Mock
     private lateinit var notificationStackScrollLayoutController:
         NotificationStackScrollLayoutController
-    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
     @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
     @Mock
     private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
-    @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
     @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
     @Mock private lateinit var ambientState: AmbientState
     @Mock private lateinit var shadeLogger: ShadeLogger
@@ -161,7 +157,6 @@
         val featureFlags = FakeFeatureFlags()
         featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
         featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES)
         testScope = TestScope()
         controller =
@@ -176,9 +171,7 @@
                 panelExpansionInteractor,
                 ShadeExpansionStateManager(),
                 notificationStackScrollLayoutController,
-                statusBarKeyguardViewManager,
                 statusBarWindowStateController,
-                lockIconViewController,
                 centralSurfaces,
                 dozeServiceHost,
                 dozeScrimController,
@@ -221,48 +214,18 @@
         }
 
     @Test
-    fun testInterceptTouchWhenShowingAltAuth() =
-        testScope.runTest {
-            captureInteractionEventHandler()
-
-            // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
-            whenever(statusBarStateController.isDozing).thenReturn(false)
-            whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(any())).thenReturn(true)
-            whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false)
-
-            // THEN we should intercept touch
-            assertThat(interactionEventHandler.shouldInterceptTouchEvent(mock())).isTrue()
-        }
-
-    @Test
     fun testNoInterceptTouch() =
         testScope.runTest {
             captureInteractionEventHandler()
 
-            // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept
+            // WHEN not dozing, drag down helper doesn't want to intercept
             whenever(statusBarStateController.isDozing).thenReturn(false)
-            whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(any()))
-                .thenReturn(false)
             whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false)
 
             // THEN we shouldn't intercept touch
             assertThat(interactionEventHandler.shouldInterceptTouchEvent(mock())).isFalse()
         }
 
-    @Test
-    fun testHandleTouchEventWhenShowingAltAuth() =
-        testScope.runTest {
-            captureInteractionEventHandler()
-
-            // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
-            whenever(statusBarStateController.isDozing).thenReturn(false)
-            whenever(statusBarKeyguardViewManager.onTouch(any())).thenReturn(true)
-            whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false)
-
-            // THEN we should handle the touch
-            assertThat(interactionEventHandler.handleTouchEvent(mock())).isTrue()
-        }
-
     private fun captureInteractionEventHandler() {
         verify(underTest).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
         interactionEventHandler = interactionEventHandlerCaptor.value
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 905301e..943fb62 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -74,6 +75,7 @@
     @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
     @Mock private lateinit var statusBarWindowController: StatusBarWindowController
+    @Mock private lateinit var statusBarWindowControllerStore: StatusBarWindowControllerStore
     @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
     @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
     @Mock private lateinit var windowManager: WindowManager
@@ -105,6 +107,8 @@
         MockitoAnnotations.initMocks(this)
         whenever(windowManager.defaultDisplay).thenReturn(display)
         whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+        whenever(statusBarWindowControllerStore.defaultDisplay)
+            .thenReturn(statusBarWindowController)
         shadeController =
             ShadeControllerImpl(
                 commandQueue,
@@ -113,7 +117,7 @@
                 keyguardStateController,
                 statusBarStateController,
                 statusBarKeyguardViewManager,
-                statusBarWindowController,
+                statusBarWindowControllerStore,
                 deviceProvisionedController,
                 notificationShadeWindowController,
                 0,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModelTest.kt
similarity index 74%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModelTest.kt
index 118dea6..69a7627 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModelTest.kt
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel
+package com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel
 
 import android.content.packageManager
 import android.graphics.drawable.BitmapDrawable
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.ColorsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.commandline.CommandRegistry
@@ -40,13 +40,13 @@
 import org.mockito.kotlin.whenever
 
 @SmallTest
-class DemoRonChipViewModelTest : SysuiTestCase() {
+class DemoNotifChipViewModelTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val commandRegistry = kosmos.commandRegistry
     private val pw = PrintWriter(StringWriter())
 
-    private val underTest = kosmos.demoRonChipViewModel
+    private val underTest = kosmos.demoNotifChipViewModel
 
     @Before
     fun setUp() {
@@ -56,61 +56,61 @@
     }
 
     @Test
-    @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
     fun chip_flagOff_hidden() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            addDemoRonChip()
+            addDemoNotifChip()
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
         }
 
     @Test
-    @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun chip_noPackage_hidden() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            commandRegistry.onShellCommand(pw, arrayOf("demo-ron"))
+            commandRegistry.onShellCommand(pw, arrayOf("demo-notif"))
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
         }
 
     @Test
-    @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun chip_hasPackage_shown() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            commandRegistry.onShellCommand(pw, arrayOf("demo-ron", "-p", "com.android.systemui"))
+            commandRegistry.onShellCommand(pw, arrayOf("demo-notif", "-p", "com.android.systemui"))
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
         }
 
     @Test
-    @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun chip_hasText_shownWithText() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
             commandRegistry.onShellCommand(
                 pw,
-                arrayOf("demo-ron", "-p", "com.android.systemui", "-t", "test")
+                arrayOf("demo-notif", "-p", "com.android.systemui", "-t", "test"),
             )
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Text::class.java)
         }
 
     @Test
-    @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun chip_supportsColor() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
             commandRegistry.onShellCommand(
                 pw,
-                arrayOf("demo-ron", "-p", "com.android.systemui", "-c", "#434343")
+                arrayOf("demo-notif", "-p", "com.android.systemui", "-c", "#434343"),
             )
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
@@ -119,28 +119,28 @@
         }
 
     @Test
-    @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun chip_hasHideArg_hidden() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
             // First, show a chip
-            addDemoRonChip()
+            addDemoNotifChip()
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
 
             // Then, hide the chip
-            commandRegistry.onShellCommand(pw, arrayOf("demo-ron", "--hide"))
+            commandRegistry.onShellCommand(pw, arrayOf("demo-notif", "--hide"))
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
         }
 
-    private fun addDemoRonChip() {
-        Companion.addDemoRonChip(commandRegistry, pw)
+    private fun addDemoNotifChip() {
+        addDemoNotifChip(commandRegistry, pw)
     }
 
     companion object {
-        fun addDemoRonChip(commandRegistry: CommandRegistry, pw: PrintWriter) {
-            commandRegistry.onShellCommand(pw, arrayOf("demo-ron", "-p", "com.android.systemui"))
+        fun addDemoNotifChip(commandRegistry: CommandRegistry, pw: PrintWriter) {
+            commandRegistry.onShellCommand(pw, arrayOf("demo-notif", "-p", "com.android.systemui"))
         }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
new file mode 100644
index 0000000..eb5d931
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2024 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.chips.notification.ui.viewmodel
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+@EnableFlags(StatusBarNotifChips.FLAG_NAME)
+class NotifChipsViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val activeNotificationListRepository = kosmos.activeNotificationListRepository
+
+    private val underTest = kosmos.notifChipsViewModel
+
+    @Test
+    fun chips_noNotifs_empty() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            setNotifs(emptyList())
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
+    fun chips_notifMissingStatusBarChipIconView_empty() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            setNotifs(listOf(activeNotificationModel(key = "notif", statusBarChipIcon = null)))
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
+    fun chips_oneNotif_statusBarIconViewMatches() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            val icon = mock<StatusBarIconView>()
+            setNotifs(listOf(activeNotificationModel(key = "notif", statusBarChipIcon = icon)))
+
+            assertThat(latest).hasSize(1)
+            val chip = latest!![0]
+            assertThat(chip).isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
+            assertThat(chip.icon).isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(icon))
+        }
+
+    @Test
+    fun chips_twoNotifs_twoChips() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            val firstIcon = mock<StatusBarIconView>()
+            val secondIcon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(key = "notif1", statusBarChipIcon = firstIcon),
+                    activeNotificationModel(key = "notif2", statusBarChipIcon = secondIcon),
+                )
+            )
+
+            assertThat(latest).hasSize(2)
+            assertIsNotifChip(latest!![0], firstIcon)
+            assertIsNotifChip(latest!![1], secondIcon)
+        }
+
+    private fun setNotifs(notifs: List<ActiveNotificationModel>) {
+        activeNotificationListRepository.activeNotifications.value =
+            ActiveNotificationsStore.Builder()
+                .apply { notifs.forEach { addIndividualNotif(it) } }
+                .build()
+        testScope.runCurrent()
+    }
+
+    companion object {
+        fun assertIsNotifChip(latest: OngoingActivityChipModel?, expectedIcon: StatusBarIconView) {
+            assertThat(latest)
+                .isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
+            assertThat((latest as OngoingActivityChipModel.Shown).icon)
+                .isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(expectedIcon))
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 26ce7b9..e96def6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -25,7 +25,6 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.coroutines.collectLastValue
@@ -40,7 +39,8 @@
 import com.android.systemui.screenrecord.data.repository.screenRecordRepository
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
-import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.demoRonChipViewModel
+import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.demoNotifChipViewModel
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -66,13 +66,11 @@
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
-/**
- * Tests for [OngoingActivityChipsViewModel] when the [FLAG_STATUS_BAR_RON_CHIPS] flag is disabled.
- */
+/** Tests for [OngoingActivityChipsViewModel] when the [StatusBarNotifChips] flag is disabled. */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
-@DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+@DisableFlags(StatusBarNotifChips.FLAG_NAME)
 class OngoingActivityChipsViewModelTest : SysuiTestCase() {
     private val kosmos = Kosmos().also { it.testCase = this }
     private val testScope = kosmos.testScope
@@ -99,11 +97,11 @@
     @Before
     fun setUp() {
         setUpPackageManagerForMediaProjection(kosmos)
-        kosmos.demoRonChipViewModel.start()
+        kosmos.demoNotifChipViewModel.start()
         val icon =
             BitmapDrawable(
                 context.resources,
-                Bitmap.createBitmap(/* width= */ 100, /* height= */ 100, Bitmap.Config.ARGB_8888)
+                Bitmap.createBitmap(/* width= */ 100, /* height= */ 100, Bitmap.Config.ARGB_8888),
             )
         whenever(kosmos.packageManager.getApplicationIcon(any<String>())).thenReturn(icon)
     }
@@ -325,7 +323,7 @@
             latest: OngoingActivityChipModel?,
             chipView: View,
             dialog: SystemUIDialog,
-            kosmos: Kosmos
+            kosmos: Kosmos,
         ): DialogInterface.OnClickListener {
             // Capture the action that would get invoked when the user clicks "Stop" on the dialog
             lateinit var dialogStopAction: DialogInterface.OnClickListener
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
similarity index 77%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index 631120b..b12d7c5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithRonsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -24,7 +24,6 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
@@ -34,10 +33,13 @@
 import com.android.systemui.res.R
 import com.android.systemui.screenrecord.data.model.ScreenRecordModel
 import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
-import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.DemoRonChipViewModelTest.Companion.addDemoRonChip
-import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.demoRonChipViewModel
+import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.DemoNotifChipViewModelTest.Companion.addDemoNotifChip
+import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.demoNotifChipViewModel
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.chips.notification.ui.viewmodel.NotifChipsViewModelTest.Companion.assertIsNotifChip
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
@@ -46,6 +48,10 @@
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog
 import com.android.systemui.statusbar.commandline.commandRegistry
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
@@ -67,14 +73,12 @@
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 
-/**
- * Tests for [OngoingActivityChipsViewModel] when the [FLAG_STATUS_BAR_RON_CHIPS] flag is enabled.
- */
+/** Tests for [OngoingActivityChipsViewModel] when the [StatusBarNotifChips] flag is enabled. */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
-@EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
-class OngoingActivityChipsWithRonsViewModelTest : SysuiTestCase() {
+@EnableFlags(StatusBarNotifChips.FLAG_NAME)
+class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val systemClock = kosmos.fakeSystemClock
@@ -83,6 +87,7 @@
     private val screenRecordState = kosmos.screenRecordRepository.screenRecordState
     private val mediaProjectionState = kosmos.fakeMediaProjectionRepository.mediaProjectionState
     private val callRepo = kosmos.ongoingCallRepository
+    private val activeNotificationListRepository = kosmos.activeNotificationListRepository
 
     private val pw = PrintWriter(StringWriter())
 
@@ -103,16 +108,16 @@
     @Before
     fun setUp() {
         setUpPackageManagerForMediaProjection(kosmos)
-        kosmos.demoRonChipViewModel.start()
+        kosmos.demoNotifChipViewModel.start()
         val icon =
             BitmapDrawable(
                 context.resources,
-                Bitmap.createBitmap(/* width= */ 100, /* height= */ 100, Bitmap.Config.ARGB_8888)
+                Bitmap.createBitmap(/* width= */ 100, /* height= */ 100, Bitmap.Config.ARGB_8888),
             )
         whenever(kosmos.packageManager.getApplicationIcon(any<String>())).thenReturn(icon)
     }
 
-    // Even though the `primaryChip` flow isn't used when the RONs flag is on, still test that the
+    // Even though the `primaryChip` flow isn't used when the notifs flag is on, still test that the
     // flow has the right behavior to verify that we don't break any existing functionality.
 
     @Test
@@ -249,13 +254,13 @@
         testScope.runTest {
             screenRecordState.value = ScreenRecordModel.Recording
             callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
-            addDemoRonChip(commandRegistry, pw)
+            addDemoNotifChip(commandRegistry, pw)
 
             val latest by collectLastValue(underTest.chips)
 
             assertIsScreenRecordChip(latest!!.primary)
             assertIsCallChip(latest!!.secondary)
-            // Demo RON chip is dropped
+            // Demo notif chip is dropped
         }
 
     @Test
@@ -288,10 +293,101 @@
         }
 
     @Test
+    fun chips_singleNotifChip_primaryIsNotifSecondaryIsHidden() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            val icon = mock<StatusBarIconView>()
+            setNotifs(listOf(activeNotificationModel(key = "notif", statusBarChipIcon = icon)))
+
+            assertIsNotifChip(latest!!.primary, icon)
+            assertThat(latest!!.secondary).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+        }
+
+    @Test
+    fun chips_twoNotifChips_primaryAndSecondaryAreNotifsInOrder() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            val firstIcon = mock<StatusBarIconView>()
+            val secondIcon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(key = "firstNotif", statusBarChipIcon = firstIcon),
+                    activeNotificationModel(key = "secondNotif", statusBarChipIcon = secondIcon),
+                )
+            )
+
+            assertIsNotifChip(latest!!.primary, firstIcon)
+            assertIsNotifChip(latest!!.secondary, secondIcon)
+        }
+
+    @Test
+    fun chips_threeNotifChips_topTwoShown() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            val firstIcon = mock<StatusBarIconView>()
+            val secondIcon = mock<StatusBarIconView>()
+            val thirdIcon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(key = "firstNotif", statusBarChipIcon = firstIcon),
+                    activeNotificationModel(key = "secondNotif", statusBarChipIcon = secondIcon),
+                    activeNotificationModel(key = "thirdNotif", statusBarChipIcon = thirdIcon),
+                )
+            )
+
+            assertIsNotifChip(latest!!.primary, firstIcon)
+            assertIsNotifChip(latest!!.secondary, secondIcon)
+        }
+
+    @Test
+    fun chips_callAndNotifs_primaryIsCallSecondaryIsNotif() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
+            val firstIcon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(key = "firstNotif", statusBarChipIcon = firstIcon),
+                    activeNotificationModel(
+                        key = "secondNotif",
+                        statusBarChipIcon = mock<StatusBarIconView>(),
+                    ),
+                )
+            )
+
+            assertIsCallChip(latest!!.primary)
+            assertIsNotifChip(latest!!.secondary, firstIcon)
+        }
+
+    @Test
+    fun chips_screenRecordAndCallAndNotifs_notifsNotShown() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chips)
+
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
+            screenRecordState.value = ScreenRecordModel.Recording
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = mock<StatusBarIconView>(),
+                    )
+                )
+            )
+
+            assertIsScreenRecordChip(latest!!.primary)
+            assertIsCallChip(latest!!.secondary)
+        }
+
+    @Test
     fun primaryChip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
         testScope.runTest {
             // Start with just the lowest priority chip shown
-            addDemoRonChip(commandRegistry, pw)
+            addDemoNotifChip(commandRegistry, pw)
             // And everything else hidden
             callRepo.setOngoingCallState(OngoingCallModel.NoCall)
             mediaProjectionState.value = MediaProjectionState.NotProjecting
@@ -299,7 +395,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsDemoRonChip(latest)
+            assertIsDemoNotifChip(latest)
 
             // WHEN the higher priority call chip is added
             callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
@@ -333,7 +429,7 @@
             mediaProjectionState.value =
                 MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
             callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
-            addDemoRonChip(commandRegistry, pw)
+            addDemoNotifChip(commandRegistry, pw)
 
             val latest by collectLastValue(underTest.primaryChip)
 
@@ -355,15 +451,15 @@
             // WHEN the higher priority call is removed
             callRepo.setOngoingCallState(OngoingCallModel.NoCall)
 
-            // THEN the lower priority demo RON is used
-            assertIsDemoRonChip(latest)
+            // THEN the lower priority demo notif is used
+            assertIsDemoNotifChip(latest)
         }
 
     @Test
     fun chips_movesChipsAroundAccordingToPriority() =
         testScope.runTest {
             // Start with just the lowest priority chip shown
-            addDemoRonChip(commandRegistry, pw)
+            addDemoNotifChip(commandRegistry, pw)
             // And everything else hidden
             callRepo.setOngoingCallState(OngoingCallModel.NoCall)
             mediaProjectionState.value = MediaProjectionState.NotProjecting
@@ -371,16 +467,16 @@
 
             val latest by collectLastValue(underTest.chips)
 
-            assertIsDemoRonChip(latest!!.primary)
+            assertIsDemoNotifChip(latest!!.primary)
             assertThat(latest!!.secondary).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
 
             // WHEN the higher priority call chip is added
             callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
 
-            // THEN the higher priority call chip is used as primary and demo ron is demoted to
+            // THEN the higher priority call chip is used as primary and demo notif is demoted to
             // secondary
             assertIsCallChip(latest!!.primary)
-            assertIsDemoRonChip(latest!!.secondary)
+            assertIsDemoNotifChip(latest!!.secondary)
 
             // WHEN the higher priority media projection chip is added
             mediaProjectionState.value =
@@ -391,7 +487,7 @@
                 )
 
             // THEN the higher priority media projection chip is used as primary and call is demoted
-            // to secondary (and demo RON is dropped altogether)
+            // to secondary (and demo notif is dropped altogether)
             assertIsShareToAppChip(latest!!.primary)
             assertIsCallChip(latest!!.secondary)
 
@@ -405,15 +501,15 @@
             screenRecordState.value = ScreenRecordModel.DoingNothing
             callRepo.setOngoingCallState(OngoingCallModel.NoCall)
 
-            // THEN media projection and demo RON remain
+            // THEN media projection and demo notif remain
             assertIsShareToAppChip(latest!!.primary)
-            assertIsDemoRonChip(latest!!.secondary)
+            assertIsDemoNotifChip(latest!!.secondary)
 
             // WHEN media projection is dropped
             mediaProjectionState.value = MediaProjectionState.NotProjecting
 
-            // THEN demo RON is promoted to primary
-            assertIsDemoRonChip(latest!!.primary)
+            // THEN demo notif is promoted to primary
+            assertIsDemoNotifChip(latest!!.primary)
             assertThat(latest!!.secondary).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
         }
 
@@ -526,9 +622,17 @@
             assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden(shouldAnimate = false))
         }
 
-    private fun assertIsDemoRonChip(latest: OngoingActivityChipModel?) {
+    private fun assertIsDemoNotifChip(latest: OngoingActivityChipModel?) {
         assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
         assertThat((latest as OngoingActivityChipModel.Shown).icon)
             .isInstanceOf(OngoingActivityChipModel.ChipIcon.FullColorAppIcon::class.java)
     }
+
+    private fun setNotifs(notifs: List<ActiveNotificationModel>) {
+        activeNotificationListRepository.activeNotifications.value =
+            ActiveNotificationsStore.Builder()
+                .apply { notifs.forEach { addIndividualNotif(it) } }
+                .build()
+        testScope.runCurrent()
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
index 9142972..f64387c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.fragments.FragmentHostManager
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import org.junit.Assert.assertThrows
@@ -39,7 +40,8 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class StatusBarInitializerTest : SysuiTestCase() {
-    val windowController = mock(StatusBarWindowController::class.java)
+    private val windowController = mock(StatusBarWindowController::class.java)
+    private val windowControllerStore = mock(StatusBarWindowControllerStore::class.java)
 
     @Before
     fun setup() {
@@ -52,15 +54,16 @@
         whenever(fragmentHostManager.fragmentManager).thenReturn(fragmentManager)
         whenever(fragmentManager.beginTransaction()).thenReturn(transaction)
         whenever(transaction.replace(any(), any(), any())).thenReturn(transaction)
-
+        whenever(windowControllerStore.defaultDisplay).thenReturn(windowController)
         whenever(windowController.fragmentHostManager).thenReturn(fragmentHostManager)
     }
 
     val underTest =
         StatusBarInitializerImpl(
-            windowController,
-            { mock(CollapsedStatusBarFragment::class.java) },
-            setOf(),
+            displayId = context.displayId,
+            statusBarWindowControllerStore = windowControllerStore,
+            collapsedStatusBarFragmentProvider = { mock(CollapsedStatusBarFragment::class.java) },
+            creationListeners = setOf(),
         )
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
index 5803365..bb3fb1e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
@@ -44,7 +44,7 @@
 import com.android.systemui.statusbar.window.data.model.StatusBarWindowState
 import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStateRepositoryStore
 import com.android.systemui.statusbar.window.data.repository.statusBarWindowStateRepositoryStore
-import com.android.systemui.statusbar.window.fakeStatusBarWindowController
+import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
 import com.android.systemui.testKosmos
 import com.android.wm.shell.bubbles.bubbles
 import com.google.common.truth.Truth.assertThat
@@ -67,7 +67,7 @@
         }
     private val testScope = kosmos.testScope
     private val statusBarViewController = kosmos.mockPhoneStatusBarViewController
-    private val statusBarWindowController = kosmos.fakeStatusBarWindowController
+    private val statusBarWindowControllerStore = kosmos.fakeStatusBarWindowControllerStore
     private val statusBarModeRepository = kosmos.fakeStatusBarModeRepository
     private val pluginDependencyProvider = kosmos.mockPluginDependencyProvider
     private val notificationShadeWindowViewController =
@@ -94,7 +94,7 @@
     fun start_attachesWindow() {
         orchestrator.start()
 
-        assertThat(statusBarWindowController.isAttached).isTrue()
+        assertThat(statusBarWindowControllerStore.defaultDisplay.isAttached).isTrue()
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
index 984bda1..a629b24 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
@@ -53,6 +54,7 @@
 
     @get:Rule val animatorTestRule = AnimatorTestRule(this)
     @Mock private lateinit var sbWindowController: StatusBarWindowController
+    @Mock private lateinit var sbWindowControllerStore: StatusBarWindowControllerStore
     @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider
 
     private var testView = TestView(mContext)
@@ -61,7 +63,7 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-
+        whenever(sbWindowControllerStore.defaultDisplay).thenReturn(sbWindowController)
         // StatusBarWindowController is mocked. The addViewToWindow function needs to be mocked to
         // ensure that the chip view is added to a parent view
         whenever(sbWindowController.addViewToWindow(any(), any())).then {
@@ -93,8 +95,8 @@
         controller =
             SystemEventChipAnimationController(
                 context = mContext,
-                statusBarWindowController = sbWindowController,
-                contentInsetsProvider = insetsProvider
+                statusBarWindowControllerStore = sbWindowControllerStore,
+                contentInsetsProvider = insetsProvider,
             )
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
index 35e4047..97fa6eb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
@@ -31,6 +31,7 @@
 @RunWith(AndroidJUnit4::class)
 class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
     private var isStarted = false
+    private var wasStarted = false
     private var scrimOffset = 0f
     private var contentHeight = 0f
     private var isCurrentGestureOverscroll = false
@@ -46,7 +47,10 @@
             minVisibleScrimHeight = { MIN_VISIBLE_SCRIM_HEIGHT },
             isCurrentGestureOverscroll = { isCurrentGestureOverscroll },
             onStart = { isStarted = true },
-            onStop = { isStarted = false },
+            onStop = {
+                wasStarted = true
+                isStarted = false
+            },
         )
 
     @Test
@@ -180,6 +184,7 @@
             )
 
         assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+        assertThat(wasStarted).isEqualTo(false)
         assertThat(isStarted).isEqualTo(false)
     }
 
@@ -196,7 +201,9 @@
             )
 
         assertThat(offsetConsumed).isEqualTo(Offset.Zero)
-        assertThat(isStarted).isEqualTo(true)
+        // Returning 0 offset will immediately stop the connection
+        assertThat(wasStarted).isEqualTo(true)
+        assertThat(isStarted).isEqualTo(false)
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index 8d678ef..bf14472 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -21,7 +21,6 @@
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.FlagsParameterization
 import androidx.test.filters.SmallTest
-import com.android.app.tracing.coroutines.flow.map
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.DisableSceneContainer
@@ -51,6 +50,7 @@
 import com.android.systemui.util.ui.value
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
index 1797995..bac79a9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
@@ -56,6 +56,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -94,6 +95,7 @@
     @Mock private lateinit var activityTransitionAnimator: ActivityTransitionAnimator
     @Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager
     @Mock private lateinit var statusBarWindowController: StatusBarWindowController
+    @Mock private lateinit var statusBarWindowControllerStore: StatusBarWindowControllerStore
     @Mock private lateinit var notifShadeWindowController: NotificationShadeWindowController
     @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
     @Mock private lateinit var keyguardStateController: KeyguardStateController
@@ -112,6 +114,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        `when`(statusBarWindowControllerStore.defaultDisplay).thenReturn(statusBarWindowController)
         underTest =
             LegacyActivityStarterInternalImpl(
                 centralSurfacesOptLazy = { Optional.of(centralSurfaces) },
@@ -128,7 +131,7 @@
                 context = context,
                 displayId = DISPLAY_ID,
                 lockScreenUserManager = lockScreenUserManager,
-                statusBarWindowController = statusBarWindowController,
+                statusBarWindowControllerStore = statusBarWindowControllerStore,
                 wakefulnessLifecycle = wakefulnessLifecycle,
                 keyguardStateController = keyguardStateController,
                 statusBarStateController = statusBarStateController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 1d74331..94753f7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -34,7 +34,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -43,9 +42,7 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.service.trust.TrustAgentService;
 import android.testing.TestableLooper;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
@@ -67,7 +64,6 @@
 import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.TrustGrantFlags;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
@@ -580,22 +576,6 @@
     }
 
     @Test
-    @DisableSceneContainer
-    @DisableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void testShowAlternateBouncer_unlockingWithBiometricAllowed() {
-        // GIVEN will show alternate bouncer
-        when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
-        when(mAlternateBouncerInteractor.show()).thenReturn(true);
-
-        // WHEN showGenericBouncer is called
-        mStatusBarKeyguardViewManager.showBouncer(true);
-
-        // THEN alt auth bouncer is shown
-        verify(mAlternateBouncerInteractor).show();
-        verify(mPrimaryBouncerInteractor, never()).show(anyBoolean());
-    }
-
-    @Test
     public void testUpdateResources_delegatesToBouncer() {
         mStatusBarKeyguardViewManager.updateResources();
 
@@ -841,145 +821,6 @@
     }
 
     @Test
-    @EnableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void handleDispatchTouchEvent_alternateBouncerViewFlagEnabled() {
-        mStatusBarKeyguardViewManager.addCallback(mCallback);
-
-        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // THEN the touch is not acted upon
-        verify(mCallback, never()).onTouch(any());
-    }
-
-    @Test
-    @EnableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void onInterceptTouch_alternateBouncerViewFlagEnabled() {
-        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // THEN the touch is not intercepted
-        assertFalse(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-        ));
-    }
-
-    @Test
-    public void handleDispatchTouchEvent_alternateBouncerNotVisible() {
-        mStatusBarKeyguardViewManager.addCallback(mCallback);
-
-        // GIVEN the alternate bouncer is visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
-
-        // THEN handleDispatchTouchEvent doesn't use the touches
-        assertFalse(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-        ));
-        assertFalse(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-        ));
-        assertFalse(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
-        ));
-
-        // THEN the touch is not acted upon
-        verify(mCallback, never()).onTouch(any());
-    }
-
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void handleDispatchTouchEvent_shouldInterceptTouchAndHandleTouch() {
-        mStatusBarKeyguardViewManager.addCallback(mCallback);
-
-        // GIVEN the alternate bouncer is visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // GIVEN all touches are NOT the udfps overlay
-        when(mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(any())).thenReturn(false);
-
-        // THEN handleDispatchTouchEvent eats/intercepts the touches so motion events aren't sent
-        // to its child views (handleDispatchTouchEvent returns true)
-        assertTrue(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-        ));
-        assertTrue(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-        ));
-        assertTrue(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
-        ));
-
-        // THEN the touch is acted upon once for each dispatchTOuchEvent call
-        verify(mCallback, times(3)).onTouch(any());
-    }
-
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void handleDispatchTouchEvent_shouldInterceptTouchButNotHandleTouch() {
-        mStatusBarKeyguardViewManager.addCallback(mCallback);
-
-        // GIVEN the alternate bouncer is visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // GIVEN all touches are within the udfps overlay
-        when(mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(any())).thenReturn(true);
-
-        // THEN handleDispatchTouchEvent eats/intercepts the touches so motion events aren't sent
-        // to its child views (handleDispatchTouchEvent returns true)
-        assertTrue(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-        ));
-        assertTrue(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-        ));
-        assertTrue(mStatusBarKeyguardViewManager.dispatchTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
-        ));
-
-        // THEN the touch is NOT acted upon at the moment
-        verify(mCallback, never()).onTouch(any());
-    }
-
-    @Test
-    @DisableSceneContainer
-    public void shouldInterceptTouch_alternateBouncerNotVisible() {
-        // GIVEN the alternate bouncer is not visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
-
-        // THEN no motion events are intercepted
-        assertFalse(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-        ));
-        assertFalse(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-        ));
-        assertFalse(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
-        ));
-    }
-
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void shouldInterceptTouch_alternateBouncerVisible() {
-        // GIVEN the alternate bouncer is visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // THEN all motion events are intercepted
-        assertTrue(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-        ));
-        assertTrue(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-        ));
-        assertTrue(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
-        ));
-    }
-
-    @Test
     public void alternateBouncerToShowPrimaryBouncer_updatesScrimControllerOnce() {
         // GIVEN the alternate bouncer has shown and calls to hide()  will result in successfully
         // hiding it
@@ -997,106 +838,6 @@
 
     @Test
     @DisableSceneContainer
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void alternateBouncerOnTouch_actionDownThenUp_noMinTimeShown_noHideAltBouncer() {
-        reset(mAlternateBouncerInteractor);
-
-        // GIVEN the alternate bouncer has shown for a minimum amount of time
-        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(false);
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        when(mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(any())).thenReturn(false);
-
-        // WHEN ACTION_DOWN and ACTION_UP touch event comes
-        boolean touchHandledDown = mStatusBarKeyguardViewManager.onTouch(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
-        when(mAlternateBouncerInteractor.getReceivedDownTouch()).thenReturn(true);
-        boolean touchHandledUp = mStatusBarKeyguardViewManager.onTouch(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0));
-
-        // THEN the touches are handled (doesn't let touches through to underlying views)
-        assertTrue(touchHandledDown);
-        assertTrue(touchHandledUp);
-
-        // THEN alternate bouncer does NOT attempt to hide since min showing time wasn't met
-        verify(mAlternateBouncerInteractor, never()).hide();
-    }
-
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void alternateBouncerOnTouch_actionDownThenUp_handlesTouch_hidesAltBouncer() {
-        reset(mAlternateBouncerInteractor);
-
-        // GIVEN the alternate bouncer has shown for a minimum amount of time
-        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true);
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        when(mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(any())).thenReturn(false);
-
-        // WHEN ACTION_DOWN and ACTION_UP touch event comes
-        boolean touchHandledDown = mStatusBarKeyguardViewManager.onTouch(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
-        when(mAlternateBouncerInteractor.getReceivedDownTouch()).thenReturn(true);
-        boolean touchHandledUp = mStatusBarKeyguardViewManager.onTouch(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0));
-
-        // THEN the touches are handled
-        assertTrue(touchHandledDown);
-        assertTrue(touchHandledUp);
-
-        // THEN alternate bouncer attempts to hide
-        verify(mAlternateBouncerInteractor).hide();
-    }
-
-    @Test
-    @DisableSceneContainer
-    public void alternateBouncerOnTouch_actionUp_doesNotHideAlternateBouncer() {
-        reset(mAlternateBouncerInteractor);
-
-        // GIVEN the alternate bouncer has shown for a minimum amount of time
-        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true);
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        when(mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(any())).thenReturn(false);
-
-        // WHEN only ACTION_UP touch event comes
-        mStatusBarKeyguardViewManager.onTouch(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0));
-
-        // THEN the alternateBouncer doesn't hide
-        verify(mAlternateBouncerInteractor, never()).hide();
-    }
-
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void onTrustChanged_hideAlternateBouncerAndClearMessageArea() {
-        // GIVEN keyguard update monitor callback is registered
-        verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallback.capture());
-
-        reset(mKeyguardUpdateMonitor);
-        reset(mKeyguardMessageAreaController);
-
-        // GIVEN alternate bouncer state = not visible
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
-
-        // WHEN the device is trusted by active unlock
-        mKeyguardUpdateMonitorCallback.getValue().onTrustGrantedForCurrentUser(
-                true,
-                true,
-                new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD
-                        | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE),
-                null
-        );
-
-        // THEN the false visibility state is propagated to the keyguardUpdateMonitor
-        verify(mKeyguardUpdateMonitor).setAlternateBouncerShowing(eq(false));
-
-        // THEN message area visibility updated to FALSE with empty message
-        verify(mKeyguardMessageAreaController).setIsVisible(eq(false));
-        verify(mKeyguardMessageAreaController).setMessage(eq(""));
-    }
-
-    @Test
-    @DisableSceneContainer
     @DisableFlags(Flags.FLAG_SIM_PIN_RACE_CONDITION_ON_RESTART)
     public void testShowBouncerOrKeyguard_needsFullScreen() {
         when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
index 597e2e4..e0d9fac 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
@@ -50,6 +50,7 @@
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.time.FakeSystemClock
@@ -74,6 +75,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
 
 private const val CALL_UID = 900
 
@@ -106,6 +108,7 @@
     @Mock private lateinit var mockActivityStarter: ActivityStarter
     @Mock private lateinit var mockIActivityManager: IActivityManager
     @Mock private lateinit var mockStatusBarWindowController: StatusBarWindowController
+    @Mock private lateinit var mockStatusBarWindowControllerStore: StatusBarWindowControllerStore
 
     private lateinit var chipView: View
 
@@ -118,6 +121,8 @@
 
         MockitoAnnotations.initMocks(this)
         val notificationCollection = mock(CommonNotifCollection::class.java)
+        whenever(mockStatusBarWindowControllerStore.defaultDisplay)
+            .thenReturn(mockStatusBarWindowController)
 
         controller =
             OngoingCallController(
@@ -131,7 +136,7 @@
                 mainExecutor,
                 mockIActivityManager,
                 DumpManager(),
-                mockStatusBarWindowController,
+                mockStatusBarWindowControllerStore,
                 mockSwipeStatusBarAwayGestureHandler,
                 statusBarModeRepository,
                 logcatLogBuffer("OngoingCallControllerViaListenerTest"),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
index dfe01bf..2ad50cc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.time.fakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -93,6 +94,7 @@
     private val mockActivityStarter = kosmos.activityStarter
     private val mockIActivityManager = mock<IActivityManager>()
     private val mockStatusBarWindowController = mock<StatusBarWindowController>()
+    private val mockStatusBarWindowControllerStore = mock<StatusBarWindowControllerStore>()
 
     private lateinit var chipView: View
 
@@ -103,6 +105,8 @@
             chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
         }
 
+        whenever(mockStatusBarWindowControllerStore.defaultDisplay)
+            .thenReturn(mockStatusBarWindowController)
         controller =
             OngoingCallController(
                 testScope.backgroundScope,
@@ -115,7 +119,7 @@
                 mainExecutor,
                 mockIActivityManager,
                 DumpManager(),
-                mockStatusBarWindowController,
+                mockStatusBarWindowControllerStore,
                 mockSwipeStatusBarAwayGestureHandler,
                 statusBarModeRepository,
                 logcatLogBuffer("OngoingCallControllerViaRepoTest"),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
index b8f5815..a4b3916 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -35,7 +35,7 @@
         val drawable =
             BitmapDrawable(
                 resources,
-                Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888)
+                Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888),
             )
         val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
         assertThat(result).isSameInstanceAs(drawable)
@@ -48,7 +48,7 @@
         val drawable =
             BitmapDrawable(
                 resources,
-                Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888)
+                Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888),
             )
 
         val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
@@ -64,4 +64,31 @@
         val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
         assertThat(result).isSameInstanceAs(drawable)
     }
+
+    @Test
+    fun testDownscaleToSize_layerDrawable_allLayersSameType_resized() {
+        val drawable =
+            resources.getDrawable(
+                com.android.systemui.tests.R.drawable.layer_drawable_all_same_type,
+                resources.newTheme(),
+            )
+
+        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+
+        assertThat(result).isNotSameInstanceAs(drawable)
+    }
+
+    /** Regression test for b/244282477. */
+    @Test
+    fun testDownscaleToSize_layerDrawable_layersAreDifferentTypes_unchanged() {
+        val drawable =
+            resources.getDrawable(
+                com.android.systemui.tests.R.drawable.layer_drawable_different_types,
+                resources.newTheme(),
+            )
+
+        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+
+        assertThat(result).isSameInstanceAs(drawable)
+    }
 }
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index fc9c917..8bef475 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -26,7 +26,7 @@
     android:clipChildren="false"
     android:layout_gravity="center_horizontal|top">
     <com.android.keyguard.KeyguardClockFrame
-        android:id="@+id/lockscreen_clock_view"
+        android:id="@id/lockscreen_clock_view"
         android:layout_width="wrap_content"
         android:layout_height="@dimen/small_clock_height"
         android:layout_alignParentStart="true"
@@ -35,7 +35,7 @@
         android:paddingStart="@dimen/clock_padding_start"
         android:visibility="invisible" />
     <com.android.keyguard.KeyguardClockFrame
-        android:id="@+id/lockscreen_clock_view_large"
+        android:id="@id/lockscreen_clock_view_large"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index 690a89a..d0a1ce8 100644
--- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
@@ -45,31 +45,26 @@
             android:tint="?android:attr/colorPrimary"
         />
 
-        <!-- Only one of [ongoing_activity_chip_time, ongoing_activity_chip_text] will ever
-             be shown at one time. -->
+        <!-- Only one of [ongoing_activity_chip_time, ongoing_activity_chip_text,
+             ongoing_activity_chip_short_time_delta] will ever be shown at one time. -->
+
+        <!-- Shows a timer, like 00:01. -->
         <com.android.systemui.statusbar.chips.ui.view.ChipChronometer
             android:id="@+id/ongoing_activity_chip_time"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:gravity="center|start"
-            android:paddingStart="@dimen/ongoing_activity_chip_icon_text_padding"
-            android:textAppearance="@android:style/TextAppearance.Material.Small"
-            android:fontFamily="@*android:string/config_headlineFontFamily"
-            android:textColor="?android:attr/colorPrimary"
+            style="@style/StatusBar.Chip.Text"
         />
 
-        <!-- Used to show generic text in the chip instead of a timer. -->
+        <!-- Shows generic text. -->
         <TextView
             android:id="@+id/ongoing_activity_chip_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:gravity="center|start"
-            android:paddingStart="@dimen/ongoing_activity_chip_icon_text_padding"
-            android:textAppearance="@android:style/TextAppearance.Material.Small"
-            android:fontFamily="@*android:string/config_headlineFontFamily"
-            android:textColor="?android:attr/colorPrimary"
+            style="@style/StatusBar.Chip.Text"
+            android:visibility="gone"
+            />
+
+        <!-- Shows a time delta in short form, like "15min" or "1hr". -->
+        <android.widget.DateTimeView
+            android:id="@+id/ongoing_activity_chip_short_time_delta"
+            style="@style/StatusBar.Chip.Text"
             android:visibility="gone"
             />
 
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 22d34eb..fbb07be 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -58,6 +58,14 @@
              android:layout_height="match_parent"
              android:visibility="invisible" />
 
+    <!-- Root for all keyguard content. It was previously located within the shade. -->
+    <com.android.systemui.keyguard.ui.view.KeyguardRootView
+        android:id="@id/keyguard_root_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        />
+
     <!-- Shared container for the notification stack. Can be positioned by either
          the keyguard_root_view or notification_panel -->
     <com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
@@ -68,14 +76,6 @@
         android:clipToPadding="false"
         />
 
-    <!-- Root for all keyguard content. It was previously located within the shade. -->
-    <com.android.systemui.keyguard.ui.view.KeyguardRootView
-        android:id="@id/keyguard_root_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        />
-
     <include layout="@layout/brightness_mirror_container" />
 
     <com.android.systemui.scrim.ScrimView
diff --git a/packages/SystemUI/res/layout/udfps_fpm_empty_view.xml b/packages/SystemUI/res/layout/udfps_fpm_empty_view.xml
deleted file mode 100644
index 4799f8c..0000000
--- a/packages/SystemUI/res/layout/udfps_fpm_empty_view.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<com.android.systemui.biometrics.UdfpsFpmEmptyView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <!-- The layout height/width are placeholders, which will be overwritten by
-     FingerprintSensorPropertiesInternal. -->
-    <View
-        android:id="@+id/udfps_enroll_accessibility_view"
-        android:layout_gravity="center"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:contentDescription="@string/accessibility_fingerprint_label"/>
-</com.android.systemui.biometrics.UdfpsFpmEmptyView>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index b5efeb5..5d5b955 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -25,6 +25,12 @@
 
     <integer name="quick_settings_num_columns">4</integer>
 
+    <!-- The number of rows in the paginated grid QuickSettings -->
+    <integer name="quick_settings_paginated_grid_num_rows">2</integer>
+
+    <!-- The number of rows in the paginated grid QuickQuickSettings -->
+    <integer name="quick_qs_paginated_grid_num_rows">1</integer>
+
     <!-- The number of columns in the infinite grid QuickSettings -->
     <integer name="quick_settings_infinite_grid_num_columns">8</integer>
 
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index fc6d20e..c661846 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -27,6 +27,12 @@
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">true</bool>
 
+    <!-- The number of rows in the paginated grid QuickSettings -->
+    <integer name="quick_settings_paginated_grid_num_rows">3</integer>
+
+    <!-- The number of rows in the paginated grid QuickQuickSettings -->
+    <integer name="quick_qs_paginated_grid_num_rows">2</integer>
+
     <!-- The number of columns in the QuickSettings -->
     <integer name="quick_settings_num_columns">2</integer>
 
diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml
index 7daad1a..f556b97 100644
--- a/packages/SystemUI/res/values-sw600dp-port/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/config.xml
@@ -21,6 +21,12 @@
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">3</integer>
 
+    <!-- The number of rows in the paginated grid QuickSettings -->
+    <integer name="quick_settings_paginated_grid_num_rows">3</integer>
+
+    <!-- The number of rows in the paginated grid QuickQuickSettings -->
+    <integer name="quick_qs_paginated_grid_num_rows">2</integer>
+
     <!-- The number of columns in the QuickSettings -->
     <integer name="quick_settings_num_columns">3</integer>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6f94f9e..16a8bc5 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -70,6 +70,12 @@
     <!-- The number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">4</integer>
 
+    <!-- The number of rows in the paginated grid QuickSettings -->
+    <integer name="quick_settings_paginated_grid_num_rows">4</integer>
+
+    <!-- The number of rows in the paginated grid QuickQuickSettings -->
+    <integer name="quick_qs_paginated_grid_num_rows">2</integer>
+
     <!-- The number of columns in the infinite grid QuickSettings -->
     <integer name="quick_settings_infinite_grid_num_columns">4</integer>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e1f25f9..7cebac2 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -70,6 +70,20 @@
         <item name="android:fontWeight">700</item>
     </style>
 
+    <style name="StatusBar" />
+    <style name="StatusBar.Chip" />
+
+    <style name="StatusBar.Chip.Text">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:gravity">center|start</item>
+        <item name="android:paddingStart">@dimen/ongoing_activity_chip_icon_text_padding</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.Material.Small</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textColor">?android:attr/colorPrimary</item>
+    </style>
+
     <style name="Chipbar" />
 
     <style name="Chipbar.Text" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title">
@@ -677,10 +691,12 @@
 
     <style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="android:windowActionBar">false</item>
+        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
         <item name="preferenceTheme">@style/TunerPreferenceTheme</item>
     </style>
 
     <style name="TunerPreferenceTheme" parent="@style/PreferenceThemeOverlay.SettingsBase">
+        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
     </style>
 
     <style name="TextAppearance.NotificationInfo.Confirmation">
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 4a96e9e..c7ea980 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -193,12 +193,16 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         if (!MigrateClocksToBlueprint.isEnabled()) {
-            mSmallClockFrame = findViewById(R.id.lockscreen_clock_view);
-            mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
+            mSmallClockFrame = findViewById(
+                    com.android.systemui.customization.R.id.lockscreen_clock_view);
+            mLargeClockFrame = findViewById(
+                    com.android.systemui.customization.R.id.lockscreen_clock_view_large);
             mStatusArea = findViewById(R.id.keyguard_status_area);
         } else {
-            removeView(findViewById(R.id.lockscreen_clock_view));
-            removeView(findViewById(R.id.lockscreen_clock_view_large));
+            removeView(findViewById(
+                    com.android.systemui.customization.R.id.lockscreen_clock_view));
+            removeView(findViewById(
+                    com.android.systemui.customization.R.id.lockscreen_clock_view_large));
         }
         onConfigChanged();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index d468f2f..7cba845 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -241,8 +241,10 @@
         mKeyguardSliceViewController.init();
 
         if (!MigrateClocksToBlueprint.isEnabled()) {
-            mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
-            mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
+            mSmallClockFrame = mView
+                .findViewById(com.android.systemui.customization.R.id.lockscreen_clock_view);
+            mLargeClockFrame = mView
+                .findViewById(com.android.systemui.customization.R.id.lockscreen_clock_view_large);
         }
 
         if (!mOnlyClock) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 63a4af9..0684824 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -534,7 +534,8 @@
         // KeyguardClockViewBinder
         if (customClockAnimation && !MigrateClocksToBlueprint.isEnabled()) {
             // Find the clock, so we can exclude it from this transition.
-            FrameLayout clockContainerView = mView.findViewById(R.id.lockscreen_clock_view_large);
+            FrameLayout clockContainerView = mView.findViewById(
+                    com.android.systemui.customization.R.id.lockscreen_clock_view_large);
 
             // The clock container can sometimes be null. If it is, just fall back to the
             // old animation rather than setting up the custom animations.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index 19d918f..5a02486 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.view.View
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -98,12 +99,12 @@
             viewsIdToTranslate =
                 setOf(
                     ViewIdToTranslate(
-                        viewId = R.id.lockscreen_clock_view_large,
+                        viewId = customR.id.lockscreen_clock_view_large,
                         direction = START,
                         shouldBeAnimated = filterKeyguardAndSplitShadeOnly
                     ),
                     ViewIdToTranslate(
-                        viewId = R.id.lockscreen_clock_view,
+                        viewId = customR.id.lockscreen_clock_view,
                         direction = START,
                         shouldBeAnimated = filterKeyguard
                     ),
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a301155..40c1f0f9 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -52,7 +52,7 @@
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.tuner.TunerService;
 
 import dagger.Lazy;
@@ -148,7 +148,7 @@
     @Inject Lazy<SystemUIDialogManager> mSystemUIDialogManagerLazy;
     @Inject Lazy<DialogTransitionAnimator> mDialogTransitionAnimatorLazy;
     @Inject Lazy<UserTracker> mUserTrackerLazy;
-    @Inject Lazy<StatusBarWindowController> mStatusBarWindowControllerLazy;
+    @Inject Lazy<StatusBarWindowControllerStore> mStatusBarWindowControllerStoreLazy;
 
     @Inject
     public Dependency() {
@@ -192,7 +192,8 @@
         mProviders.put(SystemUIDialogManager.class, mSystemUIDialogManagerLazy::get);
         mProviders.put(DialogTransitionAnimator.class, mDialogTransitionAnimatorLazy::get);
         mProviders.put(UserTracker.class, mUserTrackerLazy::get);
-        mProviders.put(StatusBarWindowController.class, mStatusBarWindowControllerLazy::get);
+        mProviders.put(
+                StatusBarWindowControllerStore.class, mStatusBarWindowControllerStoreLazy::get);
 
         Dependency.setInstance(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
deleted file mode 100644
index 242601d..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics
-
-import android.content.Context
-import android.util.AttributeSet
-
-/**
- * Class that coordinates non-HBM animations during BiometricPrompt.
- *
- * Currently doesn't draw anything.
- *
- * Note that [AuthBiometricFingerprintViewController] also shows UDFPS animations. At some point we should
- * de-dupe this if necessary.
- */
-class UdfpsBpView(context: Context, attrs: AttributeSet?) : UdfpsAnimationView(context, attrs) {
-
-    // Drawable isn't ever added to the view, so we don't currently show anything
-    private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
-
-    override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
deleted file mode 100644
index e0455b5..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics
-
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.phone.SystemUIDialogManager
-
-/**
- * Class that coordinates non-HBM animations for biometric prompt.
- */
-class UdfpsBpViewController(
-    view: UdfpsBpView,
-    statusBarStateController: StatusBarStateController,
-    shadeInteractor: ShadeInteractor,
-    systemUIDialogManager: SystemUIDialogManager,
-    dumpManager: DumpManager,
-    udfpsOverlayInteractor: UdfpsOverlayInteractor,
-) : UdfpsAnimationViewController<UdfpsBpView>(
-    view,
-    statusBarStateController,
-    shadeInteractor,
-    systemUIDialogManager,
-    dumpManager,
-    udfpsOverlayInteractor,
-) {
-    override val tag = "UdfpsBpViewController"
-
-    override fun shouldPauseAuth(): Boolean {
-        return false
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index a3904ca..2863e29 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -87,7 +87,6 @@
 import com.android.systemui.dagger.qualifiers.Application;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -98,7 +97,6 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
@@ -162,7 +160,6 @@
     @NonNull private final FalsingManager mFalsingManager;
     @NonNull private final PowerManager mPowerManager;
     @NonNull private final AccessibilityManager mAccessibilityManager;
-    @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @NonNull private final ConfigurationController mConfigurationController;
     @NonNull private final SystemClock mSystemClock;
     @NonNull private final UnlockedScreenOffAnimationController
@@ -283,7 +280,6 @@
                         mKeyguardUpdateMonitor,
                         mDialogManager,
                         mDumpManager,
-                        mLockscreenShadeTransitionController,
                         mConfigurationController,
                         mKeyguardStateController,
                         mUnlockedScreenOffAnimationController,
@@ -291,10 +287,9 @@
                         requestId,
                         reason,
                         callback,
-                        (view, event, fromUdfpsView) -> onTouch(
+                        (view, event) -> onTouch(
                             requestId,
-                            event,
-                            fromUdfpsView
+                            event
                         ),
                             mActivityTransitionAnimator,
                         mPrimaryBouncerInteractor,
@@ -374,9 +369,6 @@
                 if (mOverlay == null || mOverlay.isHiding()) {
                     return;
                 }
-                if (!DeviceEntryUdfpsRefactor.isEnabled()) {
-                    ((UdfpsView) mOverlay.getTouchOverlay()).setDebugMessage(message);
-                }
             });
         }
 
@@ -391,7 +383,7 @@
          */
         public void debugOnTouch(MotionEvent event) {
             final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L;
-            UdfpsController.this.onTouch(requestId, event, true);
+            UdfpsController.this.onTouch(requestId, event);
         }
 
         /**
@@ -449,22 +441,10 @@
         if (!mOverlayParams.equals(overlayParams)) {
             mOverlayParams = overlayParams;
 
-            if (DeviceEntryUdfpsRefactor.isEnabled()) {
-                if (mOverlay != null && mOverlay.getRequestReason() == REASON_AUTH_KEYGUARD) {
-                    mOverlay.updateOverlayParams(mOverlayParams);
-                } else {
-                    redrawOverlay();
-                }
+            if (mOverlay != null && mOverlay.getRequestReason() == REASON_AUTH_KEYGUARD) {
+                mOverlay.updateOverlayParams(mOverlayParams);
             } else {
-                final boolean wasShowingAlternateBouncer =
-                        mAlternateBouncerInteractor.isVisibleState();
-                // When the bounds change it's always to re-create the overlay's window with new
-                // LayoutParams. If the overlay needs to be shown, this will re-create and show the
-                // overlay with the updated LayoutParams. Otherwise, the overlay will remain hidden.
                 redrawOverlay();
-                if (wasShowingAlternateBouncer) {
-                    mKeyguardViewManager.showBouncer(true);
-                }
             }
         }
     }
@@ -563,11 +543,7 @@
         }
     }
 
-    private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
-        if (!fromUdfpsView) {
-            Log.e(TAG, "ignoring the touch injected from outside of UdfpsView");
-            return false;
-        }
+    private boolean onTouch(long requestId, @NonNull MotionEvent event) {
         if (mOverlay == null) {
             Log.w(TAG, "ignoring onTouch with null overlay");
             return false;
@@ -591,13 +567,6 @@
             if (!mIsAodInterruptActive) {
                 mOnFingerDown = false;
             }
-        } else if (!DeviceEntryUdfpsRefactor.isEnabled()) {
-            if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f
-                    && !mAlternateBouncerInteractor.isVisibleState())
-                    || mPrimaryBouncerInteractor.isInTransit()) {
-                Log.w(TAG, "ignoring touch due to qsDragProcess or primaryBouncerInteractor");
-                return false;
-            }
         }
 
         final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId,
@@ -661,22 +630,13 @@
                         mStatusBarStateController.isDozing());
                 break;
 
-            case UNCHANGED:
-                if (mActivePointerId == MotionEvent.INVALID_POINTER_ID
-                        && mAlternateBouncerInteractor.isVisibleState()) {
-                    // No pointer on sensor, forward to keyguard if alternateBouncer is visible
-                    mKeyguardViewManager.onTouch(event);
-                }
-
             default:
                 break;
         }
         logBiometricTouch(processedTouch.getEvent(), data);
 
         // Always pilfer pointers that are within sensor area or when alternate bouncer is showing
-        if (mActivePointerId != MotionEvent.INVALID_POINTER_ID
-                || (mAlternateBouncerInteractor.isVisibleState()
-                && !DeviceEntryUdfpsRefactor.isEnabled())) {
+        if (mActivePointerId != MotionEvent.INVALID_POINTER_ID) {
             shouldPilfer = true;
         }
 
@@ -692,14 +652,7 @@
     }
 
     private boolean shouldTryToDismissKeyguard() {
-        boolean onKeyguard = false;
-        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-            onKeyguard = mKeyguardStateController.isShowing();
-        } else {
-            onKeyguard = mOverlay != null
-                    && mOverlay.getAnimationViewController()
-                        instanceof UdfpsKeyguardViewControllerLegacy;
-        }
+        boolean onKeyguard = mKeyguardStateController.isShowing();
         return onKeyguard
                 && mKeyguardStateController.canDismissLockScreen()
                 && !mAttemptedToDismissKeyguard;
@@ -719,7 +672,6 @@
             @NonNull FalsingManager falsingManager,
             @NonNull PowerManager powerManager,
             @NonNull AccessibilityManager accessibilityManager,
-            @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController,
             @NonNull ScreenLifecycle screenLifecycle,
             @NonNull VibratorHelper vibrator,
             @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
@@ -769,7 +721,6 @@
         mFalsingManager = falsingManager;
         mPowerManager = powerManager;
         mAccessibilityManager = accessibilityManager;
-        mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         screenLifecycle.addObserver(mScreenObserver);
         mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
         mConfigurationController = configurationController;
@@ -849,13 +800,7 @@
 
     @Override
     public void dozeTimeTick() {
-        if (mOverlay != null && mOverlay.getTouchOverlay() instanceof UdfpsView) {
-            DeviceEntryUdfpsRefactor.assertInLegacyMode();
-            final View view = mOverlay.getTouchOverlay();
-            if (view != null) {
-                ((UdfpsView) view).dozeTimeTick();
-            }
-        }
+
     }
 
     private void redrawOverlay() {
@@ -915,17 +860,8 @@
         if (!isOptical()) {
             return;
         }
-        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-            if (mUdfpsDisplayMode != null) {
-                mUdfpsDisplayMode.disable(null);
-            }
-        } else {
-            if (view != null) {
-                UdfpsView udfpsView = (UdfpsView) view;
-                if (udfpsView.isDisplayConfigured()) {
-                    udfpsView.unconfigureDisplay();
-                }
-            }
+        if (mUdfpsDisplayMode != null) {
+            mUdfpsDisplayMode.disable(null);
         }
     }
 
@@ -1118,11 +1054,7 @@
             if (mIgnoreRefreshRate) {
                 dispatchOnUiReady(requestId);
             } else {
-                if (DeviceEntryUdfpsRefactor.isEnabled()) {
                     mUdfpsDisplayMode.enable(() -> dispatchOnUiReady(requestId));
-                } else {
-                    ((UdfpsView) view).configureDisplay(() -> dispatchOnUiReady(requestId));
-                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 1bac0bc..a1efc19 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -23,8 +23,6 @@
 import android.graphics.Rect
 import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
 import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
 import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
 import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
 import android.hardware.biometrics.BiometricRequestConstants.RequestReason
@@ -42,7 +40,6 @@
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
-import androidx.annotation.LayoutRes
 import androidx.annotation.VisibleForTesting
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
 import com.android.keyguard.KeyguardUpdateMonitor
@@ -56,7 +53,6 @@
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -64,7 +60,6 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.phone.SystemUIDialogManager
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
@@ -102,7 +97,6 @@
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val dialogManager: SystemUIDialogManager,
     private val dumpManager: DumpManager,
-    private val transitionController: LockscreenShadeTransitionController,
     private val configurationController: ConfigurationController,
     private val keyguardStateController: KeyguardStateController,
     private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
@@ -110,7 +104,7 @@
     val requestId: Long,
     @RequestReason val requestReason: Int,
     private val controllerCallback: IUdfpsOverlayControllerCallback,
-    private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
+    private val onTouch: (View, MotionEvent) -> Boolean,
     private val activityTransitionAnimator: ActivityTransitionAnimator,
     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
     private val alternateBouncerInteractor: AlternateBouncerInteractor,
@@ -133,23 +127,15 @@
             .map {} // map to Unit
     private var listenForCurrentKeyguardState: Job? = null
     private var addViewRunnable: Runnable? = null
-    private var overlayViewLegacy: UdfpsView? = null
-        private set
-
     private var overlayTouchView: UdfpsTouchOverlay? = null
 
     /**
-     * Get the current UDFPS overlay touch view which is a different View depending on whether the
-     * DeviceEntryUdfpsRefactor flag is enabled or not.
+     * Get the current UDFPS overlay touch view
      *
      * @return The view, when [isShowing], else null
      */
     fun getTouchOverlay(): View? {
-        return if (DeviceEntryUdfpsRefactor.isEnabled) {
-            overlayTouchView
-        } else {
-            overlayViewLegacy
-        }
+        return overlayTouchView
     }
 
     private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams()
@@ -161,7 +147,7 @@
         WindowManager.LayoutParams(
                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 0 /* flags set in computeLayoutParams() */,
-                PixelFormat.TRANSLUCENT
+                PixelFormat.TRANSLUCENT,
             )
             .apply {
                 title = TAG
@@ -188,10 +174,6 @@
     val isHiding: Boolean
         get() = getTouchOverlay() == null
 
-    /** The animation controller if the overlay [isShowing]. */
-    val animationViewController: UdfpsAnimationViewController<*>?
-        get() = overlayViewLegacy?.animationViewController
-
     private var touchExplorationEnabled = false
 
     private fun shouldRemoveEnrollmentUi(): Boolean {
@@ -199,7 +181,7 @@
             return Settings.Global.getInt(
                 context.contentResolver,
                 SETTING_REMOVE_ENROLLMENT_UI,
-                0 /* def */
+                0, /* def */
             ) != 0
         }
         return false
@@ -212,63 +194,43 @@
             overlayParams = params
             sensorBounds = Rect(params.sensorBounds)
             try {
-                if (DeviceEntryUdfpsRefactor.isEnabled) {
-                    overlayTouchView =
-                        (inflater.inflate(R.layout.udfps_touch_overlay, null, false)
-                                as UdfpsTouchOverlay)
-                            .apply {
-                                // This view overlaps the sensor area
-                                // prevent it from being selectable during a11y
-                                if (requestReason.isImportantForAccessibility()) {
-                                    importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
-                                }
-
-                                addViewNowOrLater(this, null)
-                                when (requestReason) {
-                                    REASON_AUTH_KEYGUARD ->
-                                        UdfpsTouchOverlayBinder.bind(
-                                            view = this,
-                                            viewModel = deviceEntryUdfpsTouchOverlayViewModel.get(),
-                                            udfpsOverlayInteractor = udfpsOverlayInteractor,
-                                        )
-                                    else ->
-                                        UdfpsTouchOverlayBinder.bind(
-                                            view = this,
-                                            viewModel = defaultUdfpsTouchOverlayViewModel.get(),
-                                            udfpsOverlayInteractor = udfpsOverlayInteractor,
-                                        )
-                                }
-                            }
-                } else {
-                    overlayViewLegacy =
-                        (inflater.inflate(R.layout.udfps_view, null, false) as UdfpsView).apply {
-                            overlayParams = params
-                            setUdfpsDisplayModeProvider(udfpsDisplayModeProvider)
-                            val animation = inflateUdfpsAnimation(this, controller)
-                            if (animation != null) {
-                                animation.init()
-                                animationViewController = animation
-                            }
+                overlayTouchView =
+                    (inflater.inflate(R.layout.udfps_touch_overlay, null, false)
+                            as UdfpsTouchOverlay)
+                        .apply {
                             // This view overlaps the sensor area
                             // prevent it from being selectable during a11y
                             if (requestReason.isImportantForAccessibility()) {
                                 importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
                             }
 
-                            addViewNowOrLater(this, animation)
-                            sensorRect = sensorBounds
+                            addViewNowOrLater(this, null)
+                            when (requestReason) {
+                                REASON_AUTH_KEYGUARD ->
+                                    UdfpsTouchOverlayBinder.bind(
+                                        view = this,
+                                        viewModel = deviceEntryUdfpsTouchOverlayViewModel.get(),
+                                        udfpsOverlayInteractor = udfpsOverlayInteractor,
+                                    )
+                                else ->
+                                    UdfpsTouchOverlayBinder.bind(
+                                        view = this,
+                                        viewModel = defaultUdfpsTouchOverlayViewModel.get(),
+                                        udfpsOverlayInteractor = udfpsOverlayInteractor,
+                                    )
+                            }
                         }
-                }
+
                 getTouchOverlay()?.apply {
                     touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled
                     overlayTouchListener = TouchExplorationStateChangeListener {
                         if (accessibilityManager.isTouchExplorationEnabled) {
-                            setOnHoverListener { v, event -> onTouch(v, event, true) }
+                            setOnHoverListener { v, event -> onTouch(v, event) }
                             setOnTouchListener(null)
                             touchExplorationEnabled = true
                         } else {
                             setOnHoverListener(null)
-                            setOnTouchListener { v, event -> onTouch(v, event, true) }
+                            setOnTouchListener { v, event -> onTouch(v, event) }
                             touchExplorationEnabled = false
                         }
                     }
@@ -312,7 +274,6 @@
     }
 
     fun updateOverlayParams(updatedOverlayParams: UdfpsOverlayParams) {
-        DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()
         overlayParams = updatedOverlayParams
         sensorBounds = updatedOverlayParams.sensorBounds
         getTouchOverlay()?.let {
@@ -326,108 +287,11 @@
         }
     }
 
-    fun inflateUdfpsAnimation(
-        view: UdfpsView,
-        controller: UdfpsController
-    ): UdfpsAnimationViewController<*>? {
-        DeviceEntryUdfpsRefactor.assertInLegacyMode()
-
-        val isEnrollment =
-            when (requestReason) {
-                REASON_ENROLL_FIND_SENSOR,
-                REASON_ENROLL_ENROLLING -> true
-                else -> false
-            }
-
-        val filteredRequestReason =
-            if (isEnrollment && shouldRemoveEnrollmentUi()) {
-                REASON_AUTH_OTHER
-            } else {
-                requestReason
-            }
-
-        return when (filteredRequestReason) {
-            REASON_ENROLL_FIND_SENSOR,
-            REASON_ENROLL_ENROLLING -> {
-                // Enroll udfps UI is handled by settings, so use empty view here
-                UdfpsFpmEmptyViewController(
-                    view.addUdfpsView(R.layout.udfps_fpm_empty_view) {
-                        updateAccessibilityViewLocation(sensorBounds)
-                    },
-                    statusBarStateController,
-                    shadeInteractor,
-                    dialogManager,
-                    dumpManager,
-                    udfpsOverlayInteractor,
-                )
-            }
-            REASON_AUTH_KEYGUARD -> {
-                UdfpsKeyguardViewControllerLegacy(
-                    view.addUdfpsView(R.layout.udfps_keyguard_view_legacy) {
-                        updateSensorLocation(sensorBounds)
-                    },
-                    statusBarStateController,
-                    statusBarKeyguardViewManager,
-                    keyguardUpdateMonitor,
-                    dumpManager,
-                    transitionController,
-                    configurationController,
-                    keyguardStateController,
-                    unlockedScreenOffAnimationController,
-                    dialogManager,
-                    controller,
-                    activityTransitionAnimator,
-                    primaryBouncerInteractor,
-                    alternateBouncerInteractor,
-                    udfpsKeyguardAccessibilityDelegate,
-                    selectedUserInteractor,
-                    transitionInteractor,
-                    shadeInteractor,
-                    udfpsOverlayInteractor,
-                )
-            }
-            REASON_AUTH_BP -> {
-                // note: empty controller, currently shows no visual affordance
-                UdfpsBpViewController(
-                    view.addUdfpsView(R.layout.udfps_bp_view),
-                    statusBarStateController,
-                    shadeInteractor,
-                    dialogManager,
-                    dumpManager,
-                    udfpsOverlayInteractor,
-                )
-            }
-            REASON_AUTH_OTHER,
-            REASON_AUTH_SETTINGS -> {
-                UdfpsFpmEmptyViewController(
-                    view.addUdfpsView(R.layout.udfps_fpm_empty_view),
-                    statusBarStateController,
-                    shadeInteractor,
-                    dialogManager,
-                    dumpManager,
-                    udfpsOverlayInteractor,
-                )
-            }
-            else -> {
-                Log.e(TAG, "Animation for reason $requestReason not supported yet")
-                null
-            }
-        }
-    }
-
     /** Hide the overlay or return false and do nothing if it is already hidden. */
     fun hide(): Boolean {
         val wasShowing = isShowing
 
-        overlayViewLegacy?.apply {
-            if (isDisplayConfigured) {
-                unconfigureDisplay()
-            }
-            animationViewController = null
-        }
-        if (DeviceEntryUdfpsRefactor.isEnabled) {
-            udfpsDisplayModeProvider.disable(null)
-        }
+        udfpsDisplayModeProvider.disable(null)
         getTouchOverlay()?.apply {
             if (this.parent != null) {
                 windowManager.removeView(this)
@@ -440,7 +304,6 @@
             }
         }
 
-        overlayViewLegacy = null
         overlayTouchView = null
         overlayTouchListener = null
         listenForCurrentKeyguardState?.cancel()
@@ -490,7 +353,7 @@
                         Surface.rotationToString(rot) +
                         " animation=$animation" +
                         " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" +
-                        " isOccluded=${keyguardStateController.isOccluded}"
+                        " isOccluded=${keyguardStateController.isOccluded}",
                 )
             } else {
                 Log.v(TAG, "Rotate UDFPS bounds " + Surface.rotationToString(rot))
@@ -498,14 +361,14 @@
                     rotatedBounds,
                     overlayParams.naturalDisplayWidth,
                     overlayParams.naturalDisplayHeight,
-                    rot
+                    rot,
                 )
 
                 RotationUtils.rotateBounds(
                     sensorBounds,
                     overlayParams.naturalDisplayWidth,
                     overlayParams.naturalDisplayHeight,
-                    rot
+                    rot,
                 )
             }
         }
@@ -519,14 +382,7 @@
     }
 
     private fun shouldRotate(animation: UdfpsAnimationViewController<*>?): Boolean {
-        val keyguardNotShowing =
-            if (DeviceEntryUdfpsRefactor.isEnabled) {
-                !keyguardStateController.isShowing
-            } else {
-                animation !is UdfpsKeyguardViewControllerLegacy
-            }
-
-        if (keyguardNotShowing) {
+        if (!keyguardStateController.isShowing) {
             // always rotate view if we're not on the keyguard
             return true
         }
@@ -534,16 +390,6 @@
         // on the keyguard, make sure we don't rotate if we're going to sleep or not occluded
         return !(keyguardUpdateMonitor.isGoingToSleep || !keyguardStateController.isOccluded)
     }
-
-    private inline fun <reified T : View> UdfpsView.addUdfpsView(
-        @LayoutRes id: Int,
-        init: T.() -> Unit = {}
-    ): T {
-        val subView = inflater.inflate(id, null) as T
-        addView(subView)
-        subView.init()
-        return subView
-    }
 }
 
 @RequestReason
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
deleted file mode 100644
index 0838855..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics
-
-import android.content.Context
-import android.graphics.Rect
-import android.util.AttributeSet
-import android.view.View
-import android.view.ViewGroup
-import com.android.systemui.res.R
-
-/**
- * View corresponding with udfps_fpm_empty_view.xml
- *
- * Currently doesn't draw anything.
- */
-class UdfpsFpmEmptyView(
-    context: Context,
-    attrs: AttributeSet?
-) : UdfpsAnimationView(context, attrs) {
-
-    // Drawable isn't ever added to the view, so we don't currently show anything
-    private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
-
-    override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
-
-    fun updateAccessibilityViewLocation(sensorBounds: Rect) {
-        val fingerprintAccessibilityView: View =
-            requireViewById(R.id.udfps_enroll_accessibility_view)
-        val params: ViewGroup.LayoutParams = fingerprintAccessibilityView.layoutParams
-        params.width = sensorBounds.width()
-        params.height = sensorBounds.height()
-        fingerprintAccessibilityView.layoutParams = params
-        fingerprintAccessibilityView.requestLayout()
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
deleted file mode 100644
index cfbbc26..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics
-
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.phone.SystemUIDialogManager
-
-/**
- * Class that coordinates non-HBM animations for non keyguard, or biometric prompt states.
- *
- * Currently doesn't draw anything.
- */
-class UdfpsFpmEmptyViewController(
-    view: UdfpsFpmEmptyView,
-    statusBarStateController: StatusBarStateController,
-    shadeInteractor: ShadeInteractor,
-    systemUIDialogManager: SystemUIDialogManager,
-    dumpManager: DumpManager,
-    udfpsOverlayInteractor: UdfpsOverlayInteractor,
-) : UdfpsAnimationViewController<UdfpsFpmEmptyView>(
-    view,
-    statusBarStateController,
-    shadeInteractor,
-    systemUIDialogManager,
-    dumpManager,
-    udfpsOverlayInteractor,
-) {
-    override val tag = "UdfpsFpmOtherViewController"
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
deleted file mode 100644
index c3d9240..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics
-
-import android.content.res.Configuration
-import android.util.MathUtils
-import android.view.View
-import androidx.annotation.VisibleForTesting
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.animation.Interpolators
-import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.animation.ActivityTransitionAnimator
-import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.Edge
-import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
-import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
-import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
-import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
-import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.res.R
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.LockscreenShadeTransitionController
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.OccludingAppBiometricUI
-import com.android.systemui.statusbar.phone.SystemUIDialogManager
-import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import java.io.PrintWriter
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
-
-/** Class that coordinates non-HBM animations during keyguard authentication. */
-@ExperimentalCoroutinesApi
-open class UdfpsKeyguardViewControllerLegacy(
-    private val view: UdfpsKeyguardViewLegacy,
-    statusBarStateController: StatusBarStateController,
-    private val keyguardViewManager: StatusBarKeyguardViewManager,
-    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-    dumpManager: DumpManager,
-    private val lockScreenShadeTransitionController: LockscreenShadeTransitionController,
-    private val configurationController: ConfigurationController,
-    private val keyguardStateController: KeyguardStateController,
-    private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
-    systemUIDialogManager: SystemUIDialogManager,
-    private val udfpsController: UdfpsController,
-    private val activityTransitionAnimator: ActivityTransitionAnimator,
-    private val primaryBouncerInteractor: PrimaryBouncerInteractor,
-    private val alternateBouncerInteractor: AlternateBouncerInteractor,
-    private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
-    private val selectedUserInteractor: SelectedUserInteractor,
-    private val transitionInteractor: KeyguardTransitionInteractor,
-    shadeInteractor: ShadeInteractor,
-    udfpsOverlayInteractor: UdfpsOverlayInteractor,
-) :
-    UdfpsAnimationViewController<UdfpsKeyguardViewLegacy>(
-        view,
-        statusBarStateController,
-        shadeInteractor,
-        systemUIDialogManager,
-        dumpManager,
-        udfpsOverlayInteractor,
-    ) {
-    private val uniqueIdentifier = this.toString()
-    private var showingUdfpsBouncer = false
-    private var udfpsRequested = false
-    private var qsExpansion = 0f
-    private var faceDetectRunning = false
-    private var statusBarState = 0
-    private var transitionToFullShadeProgress = 0f
-    private var lastDozeAmount = 0f
-    private var panelExpansionFraction = 0f
-    private var launchTransitionFadingAway = false
-    private var isLaunchingActivity = false
-    private var activityLaunchProgress = 0f
-    private var inputBouncerExpansion = 0f
-
-    private val stateListener: StatusBarStateController.StateListener =
-        object : StatusBarStateController.StateListener {
-            override fun onStateChanged(statusBarState: Int) {
-                this@UdfpsKeyguardViewControllerLegacy.statusBarState = statusBarState
-                updateAlpha()
-                updatePauseAuth()
-            }
-        }
-
-    private val configurationListener: ConfigurationController.ConfigurationListener =
-        object : ConfigurationController.ConfigurationListener {
-            override fun onUiModeChanged() {
-                view.updateColor()
-            }
-
-            override fun onThemeChanged() {
-                view.updateColor()
-            }
-
-            override fun onConfigChanged(newConfig: Configuration) {
-                updateScaleFactor()
-                view.updatePadding()
-                view.updateColor()
-            }
-        }
-
-    private val keyguardStateControllerCallback: KeyguardStateController.Callback =
-        object : KeyguardStateController.Callback {
-            override fun onUnlockedChanged() {
-                updatePauseAuth()
-            }
-
-            override fun onLaunchTransitionFadingAwayChanged() {
-                launchTransitionFadingAway = keyguardStateController.isLaunchTransitionFadingAway
-                updatePauseAuth()
-            }
-        }
-
-    private val mActivityTransitionAnimatorListener: ActivityTransitionAnimator.Listener =
-        object : ActivityTransitionAnimator.Listener {
-            override fun onTransitionAnimationStart() {
-                isLaunchingActivity = true
-                activityLaunchProgress = 0f
-                updateAlpha()
-            }
-
-            override fun onTransitionAnimationEnd() {
-                isLaunchingActivity = false
-                updateAlpha()
-            }
-
-            override fun onTransitionAnimationProgress(linearProgress: Float) {
-                activityLaunchProgress = linearProgress
-                updateAlpha()
-            }
-        }
-
-    private val statusBarKeyguardViewManagerCallback: KeyguardViewManagerCallback =
-        object : KeyguardViewManagerCallback {
-            override fun onQSExpansionChanged(qsExpansion: Float) {
-                this@UdfpsKeyguardViewControllerLegacy.qsExpansion = qsExpansion
-                updateAlpha()
-                updatePauseAuth()
-            }
-        }
-
-    private val occludingAppBiometricUI: OccludingAppBiometricUI =
-        object : OccludingAppBiometricUI {
-            override fun requestUdfps(request: Boolean, color: Int) {
-                udfpsRequested = request
-                view.requestUdfps(request, color)
-                updateAlpha()
-                updatePauseAuth()
-            }
-
-            override fun dump(pw: PrintWriter) {
-                pw.println(tag)
-            }
-        }
-
-    override val tag: String
-        get() = TAG
-
-    override fun onInit() {
-        super.onInit()
-        keyguardViewManager.setOccludingAppBiometricUI(occludingAppBiometricUI)
-    }
-
-    init {
-        com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor.assertInLegacyMode()
-        view.repeatWhenAttached {
-            // repeatOnLifecycle CREATED (as opposed to STARTED) because the Bouncer expansion
-            // can make the view not visible; and we still want to listen for events
-            // that may make the view visible again.
-            repeatOnLifecycle(Lifecycle.State.CREATED) {
-                listenForBouncerExpansion(this)
-                listenForAlternateBouncerVisibility(this)
-                listenForOccludedToAodTransition(this)
-                listenForGoneToAodTransition(this)
-                listenForLockscreenAodTransitions(this)
-                listenForAodToOccludedTransitions(this)
-                listenForAlternateBouncerToAodTransitions(this)
-                listenForDreamingToAodTransitions(this)
-                listenForPrimaryBouncerToAodTransitions(this)
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForPrimaryBouncerToAodTransitions(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor
-                .transition(
-                    edge = Edge.create(Scenes.Bouncer, AOD),
-                    edgeWithoutSceneContainer = Edge.create(PRIMARY_BOUNCER, AOD)
-                )
-                .collect { transitionStep ->
-                    view.onDozeAmountChanged(
-                        transitionStep.value,
-                        transitionStep.value,
-                        ANIMATE_APPEAR_ON_SCREEN_OFF,
-                    )
-                }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForDreamingToAodTransitions(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor.transition(Edge.create(DREAMING, AOD)).collect { transitionStep ->
-                view.onDozeAmountChanged(
-                    transitionStep.value,
-                    transitionStep.value,
-                    ANIMATE_APPEAR_ON_SCREEN_OFF,
-                )
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForAlternateBouncerToAodTransitions(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor.transition(Edge.create(ALTERNATE_BOUNCER, AOD)).collect {
-                transitionStep ->
-                view.onDozeAmountChanged(
-                    transitionStep.value,
-                    transitionStep.value,
-                    UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN,
-                )
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForAodToOccludedTransitions(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor.transition(Edge.create(AOD, OCCLUDED)).collect { transitionStep ->
-                view.onDozeAmountChanged(
-                    1f - transitionStep.value,
-                    1f - transitionStep.value,
-                    UdfpsKeyguardViewLegacy.ANIMATION_NONE,
-                )
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForOccludedToAodTransition(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor.transition(Edge.create(OCCLUDED, AOD)).collect { transitionStep ->
-                view.onDozeAmountChanged(
-                    transitionStep.value,
-                    transitionStep.value,
-                    ANIMATE_APPEAR_ON_SCREEN_OFF,
-                )
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForGoneToAodTransition(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor
-                .transition(
-                    edge = Edge.create(Scenes.Gone, AOD),
-                    edgeWithoutSceneContainer = Edge.create(GONE, AOD)
-                )
-                .collect { transitionStep ->
-                    view.onDozeAmountChanged(
-                        transitionStep.value,
-                        transitionStep.value,
-                        ANIMATE_APPEAR_ON_SCREEN_OFF,
-                    )
-                }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForLockscreenAodTransitions(scope: CoroutineScope): Job {
-        return scope.launch {
-            transitionInteractor.transitionValue(AOD).collect {
-                view.onDozeAmountChanged(
-                    it,
-                    it,
-                    UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN,
-                )
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job {
-        return scope.launch {
-            primaryBouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float ->
-                inputBouncerExpansion = bouncerExpansion
-
-                panelExpansionFraction =
-                    if (keyguardViewManager.isPrimaryBouncerInTransit) {
-                        aboutToShowBouncerProgress(1f - bouncerExpansion)
-                    } else {
-                        1f - bouncerExpansion
-                    }
-                updateAlpha()
-                updatePauseAuth()
-            }
-        }
-    }
-
-    @VisibleForTesting
-    suspend fun listenForAlternateBouncerVisibility(scope: CoroutineScope): Job {
-        return scope.launch {
-            alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
-                showUdfpsBouncer(isVisible)
-            }
-        }
-    }
-
-    public override fun onViewAttached() {
-        super.onViewAttached()
-        alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, uniqueIdentifier)
-        val dozeAmount = statusBarStateController.dozeAmount
-        lastDozeAmount = dozeAmount
-        stateListener.onDozeAmountChanged(dozeAmount, dozeAmount)
-        statusBarStateController.addCallback(stateListener)
-        udfpsRequested = false
-        launchTransitionFadingAway = keyguardStateController.isLaunchTransitionFadingAway
-        keyguardStateController.addCallback(keyguardStateControllerCallback)
-        statusBarState = statusBarStateController.state
-        qsExpansion = keyguardViewManager.qsExpansion
-        keyguardViewManager.addCallback(statusBarKeyguardViewManagerCallback)
-        configurationController.addCallback(configurationListener)
-        updateScaleFactor()
-        view.updatePadding()
-        updateAlpha()
-        updatePauseAuth()
-        keyguardViewManager.setOccludingAppBiometricUI(occludingAppBiometricUI)
-        lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy = this
-        activityTransitionAnimator.addListener(mActivityTransitionAnimatorListener)
-        view.startIconAsyncInflate {
-            val animationViewInternal: View =
-                view.requireViewById(R.id.udfps_animation_view_internal)
-            animationViewInternal.accessibilityDelegate = udfpsKeyguardAccessibilityDelegate
-        }
-    }
-
-    public override fun onViewDetached() {
-        super.onViewDetached()
-        alternateBouncerInteractor.setAlternateBouncerUIAvailable(false, uniqueIdentifier)
-        faceDetectRunning = false
-        keyguardStateController.removeCallback(keyguardStateControllerCallback)
-        statusBarStateController.removeCallback(stateListener)
-        keyguardViewManager.removeOccludingAppBiometricUI(occludingAppBiometricUI)
-        configurationController.removeCallback(configurationListener)
-        if (lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy === this) {
-            lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy = null
-        }
-        activityTransitionAnimator.removeListener(mActivityTransitionAnimatorListener)
-        keyguardViewManager.removeCallback(statusBarKeyguardViewManagerCallback)
-    }
-
-    override fun dump(pw: PrintWriter, args: Array<String>) {
-        super.dump(pw, args)
-        pw.println("showingUdfpsAltBouncer=$showingUdfpsBouncer")
-        pw.println(
-            "altBouncerInteractor#isAlternateBouncerVisible=" +
-                "${alternateBouncerInteractor.isVisibleState()}"
-        )
-        pw.println(
-            "altBouncerInteractor#canShowAlternateBouncerForFingerprint=" +
-                "${alternateBouncerInteractor.canShowAlternateBouncerForFingerprint()}"
-        )
-        pw.println("faceDetectRunning=$faceDetectRunning")
-        pw.println("statusBarState=" + StatusBarState.toString(statusBarState))
-        pw.println("transitionToFullShadeProgress=$transitionToFullShadeProgress")
-        pw.println("qsExpansion=$qsExpansion")
-        pw.println("panelExpansionFraction=$panelExpansionFraction")
-        pw.println("unpausedAlpha=" + view.unpausedAlpha)
-        pw.println("udfpsRequestedByApp=$udfpsRequested")
-        pw.println("launchTransitionFadingAway=$launchTransitionFadingAway")
-        pw.println("lastDozeAmount=$lastDozeAmount")
-        pw.println("inputBouncerExpansion=$inputBouncerExpansion")
-        view.dump(pw)
-    }
-
-    /**
-     * Overrides non-bouncer show logic in shouldPauseAuth to still show icon.
-     *
-     * @return whether the udfpsBouncer has been newly shown or hidden
-     */
-    private fun showUdfpsBouncer(show: Boolean): Boolean {
-        if (showingUdfpsBouncer == show) {
-            return false
-        }
-        val udfpsAffordanceWasNotShowing = shouldPauseAuth()
-        showingUdfpsBouncer = show
-        if (showingUdfpsBouncer) {
-            if (udfpsAffordanceWasNotShowing) {
-                view.animateInUdfpsBouncer(null)
-            }
-            view.announceForAccessibility(
-                view.context.getString(R.string.accessibility_fingerprint_bouncer)
-            )
-        }
-        updateAlpha()
-        updatePauseAuth()
-        return true
-    }
-
-    /**
-     * Returns true if the fingerprint manager is running but we want to temporarily pause
-     * authentication. On the keyguard, we may want to show udfps when the shade is expanded, so
-     * this can be overridden with the showBouncer method.
-     */
-    override fun shouldPauseAuth(): Boolean {
-        if (showingUdfpsBouncer) {
-            return false
-        }
-        if (
-            udfpsRequested &&
-                !notificationShadeVisible &&
-                !isInputBouncerFullyVisible() &&
-                keyguardStateController.isShowing
-        ) {
-            return false
-        }
-        if (launchTransitionFadingAway) {
-            return true
-        }
-
-        // Only pause auth if we're not on the keyguard AND we're not transitioning to doze.
-        // For the UnlockedScreenOffAnimation, the statusBarState is
-        // delayed. However, we still animate in the UDFPS affordance with the
-        // unlockedScreenOffDozeAnimator.
-        if (
-            statusBarState != StatusBarState.KEYGUARD &&
-                !unlockedScreenOffAnimationController.isAnimationPlaying()
-        ) {
-            return true
-        }
-        if (isBouncerExpansionGreaterThan(.5f)) {
-            return true
-        }
-        if (
-            keyguardUpdateMonitor.getUserUnlockedWithBiometric(
-                selectedUserInteractor.getSelectedUserId()
-            )
-        ) {
-            // If the device was unlocked by a biometric, immediately hide the UDFPS icon to avoid
-            // overlap with the LockIconView. Shortly afterwards, UDFPS will stop running.
-            return true
-        }
-        return view.unpausedAlpha < 255 * .1
-    }
-
-    fun isBouncerExpansionGreaterThan(bouncerExpansionThreshold: Float): Boolean {
-        return inputBouncerExpansion >= bouncerExpansionThreshold
-    }
-
-    fun isInputBouncerFullyVisible(): Boolean {
-        return inputBouncerExpansion == 1f
-    }
-
-    override fun listenForTouchesOutsideView(): Boolean {
-        return true
-    }
-
-    /**
-     * Set the progress we're currently transitioning to the full shade. 0.0f means we're not
-     * transitioning yet, while 1.0f means we've fully dragged down. For example, start swiping down
-     * to expand the notification shade from the empty space in the middle of the lock screen.
-     */
-    fun setTransitionToFullShadeProgress(progress: Float) {
-        transitionToFullShadeProgress = progress
-        updateAlpha()
-    }
-
-    /**
-     * Update alpha for the UDFPS lock screen affordance. The AoD UDFPS visual affordance's alpha is
-     * based on the doze amount.
-     */
-    override fun updateAlpha() {
-        // Fade icon on transitions to showing the status bar or bouncer, but if mUdfpsRequested,
-        // then the keyguard is occluded by some application - so instead use the input bouncer
-        // hidden amount to determine the fade.
-        val expansion = if (udfpsRequested) getInputBouncerHiddenAmt() else panelExpansionFraction
-        var alpha: Int =
-            if (showingUdfpsBouncer) 255
-            else MathUtils.constrain(MathUtils.map(.5f, .9f, 0f, 255f, expansion), 0f, 255f).toInt()
-        if (!showingUdfpsBouncer) {
-            // swipe from top of the lockscreen to expand full QS:
-            alpha =
-                (alpha * (1.0f - Interpolators.EMPHASIZED_DECELERATE.getInterpolation(qsExpansion)))
-                    .toInt()
-
-            // swipe from the middle (empty space) of lockscreen to expand the notification shade:
-            alpha = (alpha * (1.0f - transitionToFullShadeProgress)).toInt()
-
-            // Fade out the icon if we are animating an activity launch over the lockscreen and the
-            // activity didn't request the UDFPS.
-            if (isLaunchingActivity && !udfpsRequested) {
-                val udfpsActivityLaunchAlphaMultiplier =
-                    1f -
-                        (activityLaunchProgress *
-                                (ActivityTransitionAnimator.TIMINGS.totalDuration / 83))
-                            .coerceIn(0f, 1f)
-                alpha = (alpha * udfpsActivityLaunchAlphaMultiplier).toInt()
-            }
-
-            // Fade out alpha when a dialog is shown
-            // Fade in alpha when a dialog is hidden
-            alpha = (alpha * view.dialogSuggestedAlpha).toInt()
-        }
-        view.unpausedAlpha = alpha
-    }
-
-    private fun getInputBouncerHiddenAmt(): Float {
-        return 1f - inputBouncerExpansion
-    }
-
-    /** Update the scale factor based on the device's resolution. */
-    private fun updateScaleFactor() {
-        udfpsController.mOverlayParams?.scaleFactor?.let { view.setScaleFactor(it) }
-    }
-
-    companion object {
-        const val TAG = "UdfpsKeyguardViewController"
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
deleted file mode 100644
index 6d4eea8..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics;
-
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-import android.util.MathUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
-
-import com.android.app.animation.Interpolators;
-import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
-
-import com.airbnb.lottie.LottieAnimationView;
-import com.airbnb.lottie.LottieProperty;
-import com.airbnb.lottie.model.KeyPath;
-
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * View corresponding with udfps_keyguard_view_legacy.xml
- */
-public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView {
-    private UdfpsDrawable mFingerprintDrawable; // placeholder
-    private LottieAnimationView mAodFp;
-    private LottieAnimationView mLockScreenFp;
-
-    // used when highlighting fp icon:
-    private int mTextColorPrimary;
-    private ImageView mBgProtection;
-    boolean mUdfpsRequested;
-
-    private AnimatorSet mBackgroundInAnimator = new AnimatorSet();
-    private int mAlpha; // 0-255
-    private float mScaleFactor = 1;
-    private Rect mSensorBounds = new Rect();
-
-    // AOD anti-burn-in offsets
-    private final int mMaxBurnInOffsetX;
-    private final int mMaxBurnInOffsetY;
-    private float mInterpolatedDarkAmount;
-    private int mAnimationType = ANIMATION_NONE;
-    private boolean mFullyInflated;
-    private Runnable mOnFinishInflateRunnable;
-
-    public UdfpsKeyguardViewLegacy(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mFingerprintDrawable = new UdfpsFpDrawable(context);
-
-        mMaxBurnInOffsetX = context.getResources()
-            .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
-        mMaxBurnInOffsetY = context.getResources()
-            .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
-    }
-
-    /**
-     * Inflate internal udfps view on a background thread and call the onFinishRunnable
-     * when inflation is finished.
-     */
-    public void startIconAsyncInflate(Runnable onFinishInflate) {
-        mOnFinishInflateRunnable = onFinishInflate;
-        // inflate Lottie views on a background thread in case it takes a while to inflate
-        AsyncLayoutInflater inflater = new AsyncLayoutInflater(mContext);
-        inflater.inflate(R.layout.udfps_keyguard_view_internal, this,
-                mLayoutInflaterFinishListener);
-    }
-
-    @Override
-    public UdfpsDrawable getDrawable() {
-        return mFingerprintDrawable;
-    }
-
-    @Override
-    void onSensorRectUpdated(RectF bounds) {
-        super.onSensorRectUpdated(bounds);
-        bounds.round(this.mSensorBounds);
-        postInvalidate();
-    }
-
-    @Override
-    void onDisplayConfiguring() {
-    }
-
-    @Override
-    void onDisplayUnconfigured() {
-    }
-
-    @Override
-    public boolean dozeTimeTick() {
-        updateBurnInOffsets();
-        return true;
-    }
-
-    private void updateBurnInOffsets() {
-        if (!mFullyInflated) {
-            return;
-        }
-
-        // if we're animating from screen off, we can immediately place the icon in the
-        // AoD-burn in location, else we need to translate the icon from LS => AoD.
-        final float darkAmountForAnimation = mAnimationType == ANIMATE_APPEAR_ON_SCREEN_OFF
-                ? 1f : mInterpolatedDarkAmount;
-        final float burnInOffsetX = MathUtils.lerp(0f,
-            getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
-                - mMaxBurnInOffsetX, darkAmountForAnimation);
-        final float burnInOffsetY = MathUtils.lerp(0f,
-            getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
-                - mMaxBurnInOffsetY, darkAmountForAnimation);
-        final float burnInProgress = MathUtils.lerp(0f, getBurnInProgressOffset(),
-                darkAmountForAnimation);
-
-        if (mAnimationType == ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN && !mPauseAuth) {
-            mLockScreenFp.setTranslationX(burnInOffsetX);
-            mLockScreenFp.setTranslationY(burnInOffsetY);
-            mBgProtection.setAlpha(1f - mInterpolatedDarkAmount);
-            mLockScreenFp.setAlpha(1f - mInterpolatedDarkAmount);
-        } else if (darkAmountForAnimation == 0f) {
-            // we're on the lockscreen and should use mAlpha (changes based on shade expansion)
-            mLockScreenFp.setTranslationX(0);
-            mLockScreenFp.setTranslationY(0);
-            mBgProtection.setAlpha(mAlpha / 255f);
-            mLockScreenFp.setAlpha(mAlpha / 255f);
-        } else {
-            mBgProtection.setAlpha(0f);
-            mLockScreenFp.setAlpha(0f);
-        }
-        mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount);
-
-        mAodFp.setTranslationX(burnInOffsetX);
-        mAodFp.setTranslationY(burnInOffsetY);
-        mAodFp.setProgress(burnInProgress);
-        mAodFp.setAlpha(mInterpolatedDarkAmount);
-
-        // done animating
-        final boolean doneAnimatingBetweenAodAndLS =
-                mAnimationType == ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN
-                        && (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f);
-        final boolean doneAnimatingUnlockedScreenOff =
-                mAnimationType == ANIMATE_APPEAR_ON_SCREEN_OFF
-                        && (mInterpolatedDarkAmount == 1f);
-        if (doneAnimatingBetweenAodAndLS || doneAnimatingUnlockedScreenOff) {
-            mAnimationType = ANIMATION_NONE;
-        }
-    }
-
-    void requestUdfps(boolean request, int color) {
-        mUdfpsRequested = request;
-    }
-
-    void updateColor() {
-        if (!mFullyInflated) {
-            return;
-        }
-
-        mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
-                com.android.internal.R.attr.materialColorOnSurface);
-        final int backgroundColor = Utils.getColorAttrDefaultColor(getContext(),
-                com.android.internal.R.attr.materialColorSurfaceContainerHigh);
-        mBgProtection.setImageTintList(ColorStateList.valueOf(backgroundColor));
-        mLockScreenFp.invalidate(); // updated with a valueCallback
-    }
-
-    void setScaleFactor(float scale) {
-        mScaleFactor = scale;
-    }
-
-    void updatePadding() {
-        if (mLockScreenFp == null || mAodFp == null) {
-            return;
-        }
-
-        final int defaultPaddingPx =
-                getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
-        final int padding = (int) (defaultPaddingPx * mScaleFactor);
-        mLockScreenFp.setPadding(padding, padding, padding, padding);
-        mAodFp.setPadding(padding, padding, padding, padding);
-    }
-
-    /**
-     * @param alpha between 0 and 255
-     */
-    void setUnpausedAlpha(int alpha) {
-        mAlpha = alpha;
-        updateAlpha();
-    }
-
-    /**
-     * @return alpha between 0 and 255
-     */
-    int getUnpausedAlpha() {
-        return mAlpha;
-    }
-
-    @Override
-    protected int updateAlpha() {
-        int alpha = super.updateAlpha();
-        updateBurnInOffsets();
-        return alpha;
-    }
-
-    @Override
-    int calculateAlpha() {
-        if (mPauseAuth) {
-            return 0;
-        }
-        return mAlpha;
-    }
-
-    static final int ANIMATION_NONE = 0;
-    static final int ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN = 1;
-    static final int ANIMATE_APPEAR_ON_SCREEN_OFF = 2;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ANIMATION_NONE, ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, ANIMATE_APPEAR_ON_SCREEN_OFF})
-    private @interface AnimationType {}
-
-    void onDozeAmountChanged(float linear, float eased, @AnimationType int animationType) {
-        mAnimationType = animationType;
-        mInterpolatedDarkAmount = eased;
-        updateAlpha();
-    }
-
-    void updateSensorLocation(@NonNull Rect sensorBounds) {
-        mSensorBounds.set(sensorBounds);
-    }
-
-    /**
-     * Animates in the bg protection circle behind the fp icon to highlight the icon.
-     */
-    void animateInUdfpsBouncer(Runnable onEndAnimation) {
-        if (mBackgroundInAnimator.isRunning() || !mFullyInflated) {
-            // already animating in or not yet inflated
-            return;
-        }
-
-        // fade in and scale up
-        mBackgroundInAnimator = new AnimatorSet();
-        mBackgroundInAnimator.playTogether(
-                ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 0f, 1f),
-                ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 0f, 1f),
-                ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f));
-        mBackgroundInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        mBackgroundInAnimator.setDuration(500);
-        mBackgroundInAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (onEndAnimation != null) {
-                    onEndAnimation.run();
-                }
-            }
-        });
-        mBackgroundInAnimator.start();
-    }
-
-    /**
-     * Print debugging information for this class.
-     */
-    public void dump(PrintWriter pw) {
-        pw.println("UdfpsKeyguardView (" + this + ")");
-        pw.println("    mPauseAuth=" + mPauseAuth);
-        pw.println("    mUnpausedAlpha=" + getUnpausedAlpha());
-        pw.println("    mUdfpsRequested=" + mUdfpsRequested);
-        pw.println("    mInterpolatedDarkAmount=" + mInterpolatedDarkAmount);
-        pw.println("    mAnimationType=" + mAnimationType);
-    }
-
-    private final AsyncLayoutInflater.OnInflateFinishedListener mLayoutInflaterFinishListener =
-            new AsyncLayoutInflater.OnInflateFinishedListener() {
-                @Override
-                public void onInflateFinished(View view, int resid, ViewGroup parent) {
-                    mFullyInflated = true;
-                    mAodFp = view.findViewById(R.id.udfps_aod_fp);
-                    mLockScreenFp = view.findViewById(R.id.udfps_lockscreen_fp);
-                    mBgProtection = view.findViewById(R.id.udfps_keyguard_fp_bg);
-
-                    updatePadding();
-                    updateColor();
-                    updateAlpha();
-
-                    final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-                    lp.width = mSensorBounds.width();
-                    lp.height = mSensorBounds.height();
-                    RectF relativeToView = getBoundsRelativeToView(new RectF(mSensorBounds));
-                    lp.setMarginsRelative((int) relativeToView.left, (int) relativeToView.top,
-                            (int) relativeToView.right, (int) relativeToView.bottom);
-                    parent.addView(view, lp);
-
-                    // requires call to invalidate to update the color
-                    mLockScreenFp.addValueCallback(new KeyPath("**"), LottieProperty.COLOR_FILTER,
-                            frameInfo -> new PorterDuffColorFilter(mTextColorPrimary,
-                                    PorterDuff.Mode.SRC_ATOP));
-                    mOnFinishInflateRunnable.run();
-                }
-            };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt
index 7503a8b..a105d66 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt
@@ -23,7 +23,6 @@
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
 import com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay
 import com.android.systemui.biometrics.ui.viewmodel.UdfpsTouchOverlayViewModel
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.lifecycle.repeatWhenAttached
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
@@ -42,14 +41,13 @@
         viewModel: UdfpsTouchOverlayViewModel,
         udfpsOverlayInteractor: UdfpsOverlayInteractor,
     ) {
-        if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) return
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
                         viewModel.shouldHandleTouches.collect { shouldHandleTouches ->
                             Log.d(
                                 "UdfpsTouchOverlayBinder",
-                                "[$view]: update shouldHandleTouches=$shouldHandleTouches"
+                                "[$view]: update shouldHandleTouches=$shouldHandleTouches",
                             )
                             view.isInvisible = !shouldHandleTouches
                             udfpsOverlayInteractor.setHandleTouches(shouldHandleTouches)
@@ -58,7 +56,7 @@
                     .invokeOnCompletion {
                         Log.d(
                             "UdfpsTouchOverlayBinder",
-                            "[$view-detached]: update shouldHandleTouches=false"
+                            "[$view-detached]: update shouldHandleTouches=false",
                         )
                         udfpsOverlayInteractor.setHandleTouches(false)
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index f1c3f94..22b2888 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.log.dagger.BouncerTableLog
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
@@ -88,7 +87,6 @@
     val showMessage: StateFlow<BouncerShowMessageModel?>
     val resourceUpdateRequests: StateFlow<Boolean>
     val alternateBouncerVisible: StateFlow<Boolean>
-    val alternateBouncerUIAvailable: StateFlow<Boolean>
 
     /** Last shown security mode of the primary bouncer (ie: pin/pattern/password/SIM) */
     val lastShownSecurityMode: StateFlow<KeyguardSecurityModel.SecurityMode>
@@ -126,8 +124,6 @@
 
     fun setAlternateVisible(isVisible: Boolean)
 
-    fun setAlternateBouncerUIAvailable(isAvailable: Boolean)
-
     fun setLastShownSecurityMode(securityMode: KeyguardSecurityModel.SecurityMode)
 }
 
@@ -199,9 +195,6 @@
     private val _alternateBouncerVisible = MutableStateFlow(false)
     override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow()
     override var lastAlternateBouncerVisibleTime: Long = NOT_VISIBLE
-    private val _alternateBouncerUIAvailable = MutableStateFlow(false)
-    override val alternateBouncerUIAvailable: StateFlow<Boolean> =
-        _alternateBouncerUIAvailable.asStateFlow()
 
     init {
         setUpLogging()
@@ -220,11 +213,6 @@
         _alternateBouncerVisible.value = isVisible
     }
 
-    override fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
-        DeviceEntryUdfpsRefactor.assertInLegacyMode()
-        _alternateBouncerUIAvailable.value = isAvailable
-    }
-
     override fun setPrimaryShow(isShowing: Boolean) {
         _primaryBouncerShow.value = isShowing
     }
@@ -320,9 +308,6 @@
         resourceUpdateRequests
             .logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
             .launchIn(applicationScope)
-        alternateBouncerUIAvailable
-            .logDiffsForTable(buffer, "", "IsAlternateBouncerUIAvailable", false)
-            .launchIn(applicationScope)
         alternateBouncerVisible
             .logDiffsForTable(buffer, "", "AlternateBouncerVisible", false)
             .launchIn(applicationScope)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index 0949ea4..9c2a10a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -17,22 +17,17 @@
 package com.android.systemui.bouncer.domain.interactor
 
 import android.util.Log
-import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
-import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
 import com.android.systemui.util.time.SystemClock
 import dagger.Lazy
@@ -55,13 +50,9 @@
 class AlternateBouncerInteractor
 @Inject
 constructor(
-    private val statusBarStateController: StatusBarStateController,
-    private val keyguardStateController: KeyguardStateController,
     private val bouncerRepository: KeyguardBouncerRepository,
     fingerprintPropertyRepository: FingerprintPropertyRepository,
-    private val biometricSettingsRepository: BiometricSettingsRepository,
     private val systemClock: SystemClock,
-    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val deviceEntryBiometricsAllowedInteractor:
         Lazy<DeviceEntryBiometricsAllowedInteractor>,
     private val keyguardInteractor: Lazy<KeyguardInteractor>,
@@ -73,17 +64,10 @@
     val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
     private val alternateBouncerUiAvailableFromSource: HashSet<String> = HashSet()
     val alternateBouncerSupported: StateFlow<Boolean> =
-        if (DeviceEntryUdfpsRefactor.isEnabled) {
-            fingerprintPropertyRepository.sensorType
-                .map { sensorType -> sensorType.isUdfps() || sensorType.isPowerButton() }
-                .stateIn(
-                    scope = scope,
-                    started = SharingStarted.Eagerly,
-                    initialValue = false,
-                )
-        } else {
-            bouncerRepository.alternateBouncerUIAvailable
-        }
+        fingerprintPropertyRepository.sensorType
+            .map { sensorType -> sensorType.isUdfps() || sensorType.isPowerButton() }
+            .stateIn(scope = scope, started = SharingStarted.Eagerly, initialValue = false)
+
     private val isDozingOrAod: Flow<Boolean> =
         anyOf(
                 keyguardTransitionInteractor.get().transitionValue(KeyguardState.DOZING).map {
@@ -106,7 +90,7 @@
                     combine(
                             keyguardTransitionInteractor.get().currentKeyguardState,
                             sceneInteractor.get().currentScene,
-                            ::Pair
+                            ::Pair,
                         )
                         .flatMapLatest { (currentKeyguardState, transitionState) ->
                             if (currentKeyguardState == KeyguardState.GONE) {
@@ -122,7 +106,7 @@
                                         .isFingerprintAuthCurrentlyAllowed,
                                     keyguardInteractor.get().isKeyguardDismissible,
                                     bouncerRepository.primaryBouncerShow,
-                                    isDozingOrAod
+                                    isDozingOrAod,
                                 ) {
                                     fingerprintAllowed,
                                     keyguardDismissible,
@@ -141,37 +125,17 @@
             }
             .distinctUntilChanged()
             .onEach { Log.d(TAG, "canShowAlternateBouncer changed to $it") }
-            .stateIn(
-                scope = scope,
-                started = WhileSubscribed(),
-                initialValue = false,
-            )
+            .stateIn(scope = scope, started = WhileSubscribed(), initialValue = false)
 
     /**
      * Always shows the alternate bouncer. Requesters must check [canShowAlternateBouncer]` before
      * calling this.
      */
     fun forceShow() {
-        if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) {
-            show()
-            return
-        }
         bouncerRepository.setAlternateVisible(true)
     }
 
     /**
-     * Sets the correct bouncer states to show the alternate bouncer if it can show.
-     *
-     * @return whether alternateBouncer is visible
-     * @deprecated use [forceShow] and manually check [canShowAlternateBouncer] beforehand
-     */
-    fun show(): Boolean {
-        DeviceEntryUdfpsRefactor.assertInLegacyMode()
-        bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint())
-        return isVisibleState()
-    }
-
-    /**
      * Sets the correct bouncer states to hide the bouncer. Should only be called through
      * StatusBarKeyguardViewManager until ScrimController is refactored to use
      * alternateBouncerInteractor.
@@ -189,28 +153,8 @@
         return bouncerRepository.alternateBouncerVisible.value
     }
 
-    fun setAlternateBouncerUIAvailable(isAvailable: Boolean, token: String) {
-        DeviceEntryUdfpsRefactor.assertInLegacyMode()
-        if (isAvailable) {
-            alternateBouncerUiAvailableFromSource.add(token)
-        } else {
-            alternateBouncerUiAvailableFromSource.remove(token)
-        }
-        bouncerRepository.setAlternateBouncerUIAvailable(
-            alternateBouncerUiAvailableFromSource.isNotEmpty()
-        )
-    }
-
     fun canShowAlternateBouncerForFingerprint(): Boolean {
-        if (DeviceEntryUdfpsRefactor.isEnabled) {
-            return canShowAlternateBouncer.value
-        }
-        return alternateBouncerSupported.value &&
-            biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value &&
-            !keyguardUpdateMonitor.isFingerprintLockedOut &&
-            !keyguardStateController.isUnlocked &&
-            !statusBarStateController.isDozing &&
-            !bouncerRepository.primaryBouncerShow.value
+        return canShowAlternateBouncer.value
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index 4185aed..148b9ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.bouncer.ui.viewmodel
 
 import android.annotation.StringRes
-import com.android.app.tracing.coroutines.flow.collectLatest
 import com.android.systemui.authentication.domain.interactor.AuthenticationResult
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
@@ -28,6 +27,7 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.receiveAsFlow
 
 sealed class AuthMethodBouncerViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt b/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt
index e3f1174..a695163 100644
--- a/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt
@@ -19,7 +19,7 @@
 import android.app.usage.UsageEvents
 import android.app.usage.UsageEventsQuery
 import android.app.usage.UsageStatsManager
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.systemui.common.usagestats.data.model.UsageStatsQuery
 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel
 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel.Lifecycle
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 08a7c39..8510915 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.communal
 
+import android.os.UserHandle
 import android.provider.Settings
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionKey
@@ -147,9 +148,10 @@
             .emitOnStart()
             .onEach {
                 screenTimeout =
-                    systemSettings.getInt(
+                    systemSettings.getIntForUser(
                         Settings.System.SCREEN_OFF_TIMEOUT,
                         DEFAULT_SCREEN_TIMEOUT,
+                        UserHandle.USER_CURRENT,
                     )
             }
             .launchIn(bgScope)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 3a04d02..dc24805 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -23,7 +23,7 @@
 import android.os.UserHandle
 import android.os.UserManager
 import android.provider.Settings
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionKey
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 3826fb4..428b83d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.communal.domain.interactor
 
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionKey
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
index ba96f4e..71bfe0c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
@@ -24,8 +24,7 @@
 import android.widget.FrameLayout
 import androidx.compose.ui.unit.IntSize
 import androidx.core.view.doOnLayout
-import com.android.app.tracing.coroutines.flow.flowOn
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.common.ui.view.onLayoutChanged
 import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -41,6 +40,7 @@
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
 
 object CommunalAppWidgetHostViewBinder {
     private const val TAG = "CommunalAppWidgetHostViewBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
index 87fcdd7..a519649 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
@@ -19,7 +19,7 @@
 import androidx.compose.foundation.gestures.AnchoredDraggableState
 import androidx.compose.foundation.gestures.DraggableAnchors
 import androidx.compose.runtime.snapshotFlow
-import com.android.app.tracing.coroutines.coroutineScope
+import com.android.app.tracing.coroutines.coroutineScopeTraced as coroutineScope
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.Flow
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index 07a7c7cb..d5d3a92 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -19,7 +19,7 @@
 import android.content.Context
 import android.os.Bundle
 import android.util.SizeF
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.widgets.AppWidgetHostListenerDelegate
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
index 542b988..c894267 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -21,7 +21,7 @@
 import android.content.Intent
 import android.view.View
 import android.widget.RemoteViews
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.Flags.communalWidgetTrampolineFix
 import com.android.systemui.animation.ActivityTransitionAnimator
diff --git a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt b/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
new file mode 100644
index 0000000..5b1c9c8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.coroutines
+
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import kotlin.coroutines.CoroutineContext
+
+fun newTracingContext(name: String): CoroutineContext {
+    return createCoroutineTracingContext(name) { className ->
+        className.startsWith("com.android.systemui.util.kotlin.JavaAdapter") ||
+            className.startsWith("com.android.systemui.lifecycle.RepeatWhenAttached")
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Default.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Default.java
new file mode 100644
index 0000000..1950d6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Default.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface Default {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
index b8c03c0..c464a66 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
@@ -17,25 +17,17 @@
 package com.android.systemui.deviceentry
 
 import com.android.keyguard.EmptyLockIconViewController
-import com.android.keyguard.LegacyLockIconViewController
 import com.android.keyguard.LockIconViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.data.repository.DeviceEntryRepositoryModule
 import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfigModule
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.Multibinds
 
-@Module(
-    includes =
-        [
-            DeviceEntryRepositoryModule::class,
-            FaceWakeUpTriggersConfigModule::class,
-        ],
-)
+@Module(includes = [DeviceEntryRepositoryModule::class, FaceWakeUpTriggersConfigModule::class])
 abstract class DeviceEntryModule {
     /**
      * A set of DeviceEntryIconTransitions. Ensures that this can be injected even if it's empty.
@@ -46,14 +38,9 @@
         @Provides
         @SysUISingleton
         fun provideLockIconViewController(
-            legacyLockIconViewController: Lazy<LegacyLockIconViewController>,
-            emptyLockIconViewController: Lazy<EmptyLockIconViewController>,
+            emptyLockIconViewController: Lazy<EmptyLockIconViewController>
         ): LockIconViewController {
-            return if (DeviceEntryUdfpsRefactor.isEnabled) {
-                emptyLockIconViewController.get()
-            } else {
-                legacyLockIconViewController.get()
-            }
+            return emptyLockIconViewController.get()
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 6a69136..034cb31 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.DisplayEvent
 import com.android.systemui.util.Compile
+import com.android.systemui.util.kotlin.pairwiseBy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
@@ -41,11 +42,12 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.filterIsInstance
-import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -146,11 +148,6 @@
     override val displayChangeEvent: Flow<Int> =
         allDisplayEvents.filterIsInstance<DisplayEvent.Changed>().map { event -> event.displayId }
 
-    override val displayAdditionEvent: Flow<Display?> =
-        allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map {
-            getDisplayFromDisplayManager(it.displayId)
-        }
-
     override val displayRemovalEvent: Flow<Int> =
         allDisplayEvents.filterIsInstance<DisplayEvent.Removed>().map { it.displayId }
 
@@ -212,6 +209,17 @@
      */
     override val displays: StateFlow<Set<Display>> = enabledDisplays
 
+    /**
+     * Implementation that maps from [displays], instead of [allDisplayEvents] for 2 reasons:
+     * 1. Guarantee that it emits __after__ [displays] emitted. This way it is guaranteed that
+     *    calling [getDisplay] for the newly added display will be non-null.
+     * 2. Reuse the existing instance of [Display] without a new call to [DisplayManager].
+     */
+    override val displayAdditionEvent: Flow<Display?> =
+        displays
+            .pairwiseBy { previousDisplays, currentDisplays -> currentDisplays - previousDisplays }
+            .flatMapLatest { it.asFlow() }
+
     val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
     private val ignoredDisplayIds: Flow<Set<Int>> = _ignoredDisplayIds.debugLog("ignoredDisplayIds")
 
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
index 3062475..e3fce00 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.display.data.repository
 
 import android.view.Display
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import com.android.systemui.CoreStartable
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
@@ -69,7 +69,7 @@
             backgroundApplicationScope
         } else {
             CoroutineScope(
-                backgroundDispatcher + createCoroutineTracingContext("DisplayScope$displayId")
+                backgroundDispatcher + newTracingContext("DisplayScope$displayId")
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
index 3992c3f..724f1c5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
@@ -22,6 +22,7 @@
 import android.service.dreams.DreamService
 import android.window.TaskFragmentInfo
 import com.android.systemui.controls.settings.ControlsSettingsRepository
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dreams.DreamLogger
 import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor
@@ -39,7 +40,6 @@
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 
 class HomeControlsDreamService
 @Inject
@@ -54,7 +54,8 @@
 ) : DreamService() {
 
     private val serviceJob = SupervisorJob()
-    private val serviceScope = CoroutineScope(bgDispatcher + serviceJob + createCoroutineTracingContext("HomeControlsDreamService"))
+    private val serviceScope =
+        CoroutineScope(bgDispatcher + serviceJob + newTracingContext("HomeControlsDreamService"))
     private val logger = DreamLogger(logBuffer, TAG)
     private lateinit var taskFragmentComponent: TaskFragmentComponent
     private val wakeLock: WakeLock by lazy {
diff --git a/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt b/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
index 4caf95b..7fa7da1 100644
--- a/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
@@ -16,10 +16,10 @@
 
 package com.android.systemui.education.dagger
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import com.android.systemui.CoreStartable
 import com.android.systemui.Flags
 import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.education.data.repository.ContextualEducationRepository
 import com.android.systemui.education.data.repository.UserContextualEducationRepository
@@ -57,7 +57,9 @@
         fun provideEduDataStoreScope(
             @Background bgDispatcher: CoroutineDispatcher
         ): CoroutineScope {
-            return CoroutineScope(bgDispatcher + SupervisorJob() + createCoroutineTracingContext("EduDataStoreScope"))
+            return CoroutineScope(
+                bgDispatcher + SupervisorJob() + newTracingContext("EduDataStoreScope")
+            )
         }
 
         @EduClock
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index aa1873c..162047b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -135,6 +135,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 import com.android.systemui.util.EmergencyDialerConstants;
@@ -248,7 +249,7 @@
     private final IStatusBarService mStatusBarService;
     protected final LightBarController mLightBarController;
     protected final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final StatusBarWindowController mStatusBarWindowController;
+    private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
     private final IWindowManager mIWindowManager;
     private final Executor mBackgroundExecutor;
     private final RingerModeTracker mRingerModeTracker;
@@ -364,7 +365,7 @@
             IStatusBarService statusBarService,
             LightBarController lightBarController,
             NotificationShadeWindowController notificationShadeWindowController,
-            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowControllerStore statusBarWindowControllerStore,
             IWindowManager iWindowManager,
             @Background Executor backgroundExecutor,
             UiEventLogger uiEventLogger,
@@ -400,7 +401,7 @@
         mStatusBarService = statusBarService;
         mLightBarController = lightBarController;
         mNotificationShadeWindowController = notificationShadeWindowController;
-        mStatusBarWindowController = statusBarWindowController;
+        mStatusBarWindowControllerStore = statusBarWindowControllerStore;
         mIWindowManager = iWindowManager;
         mBackgroundExecutor = backgroundExecutor;
         mRingerModeTracker = ringerModeTracker;
@@ -708,7 +709,7 @@
                 mLightBarController,
                 mKeyguardStateController,
                 mNotificationShadeWindowController,
-                mStatusBarWindowController,
+                mStatusBarWindowControllerStore.getDefaultDisplay(),
                 this::onRefresh,
                 mKeyguardShowing,
                 mPowerAdapter,
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
index e396767..1dbcb3df 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
@@ -22,7 +22,7 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.util.VelocityTracker
 import androidx.compose.ui.unit.Velocity
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
 import com.android.systemui.haptics.slider.SliderDragVelocityProvider
 import com.android.systemui.haptics.slider.SliderEventType
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 6df8355..a94df09 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -30,7 +30,7 @@
 import android.os.Binder
 import android.os.Bundle
 import android.util.Log
-import com.android.app.tracing.coroutines.runBlocking
+import com.android.app.tracing.coroutines.runBlockingTraced as runBlocking
 import com.android.systemui.SystemUIAppComponentFactoryBase
 import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
 import com.android.systemui.dagger.qualifiers.Main
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 063adc8..3230285 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -30,8 +30,6 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.keyguard.KeyguardStatusView
 import com.android.keyguard.KeyguardStatusViewController
-import com.android.keyguard.LegacyLockIconViewController
-import com.android.keyguard.LockIconView
 import com.android.keyguard.dagger.KeyguardStatusViewComponent
 import com.android.systemui.CoreStartable
 import com.android.systemui.biometrics.ui.binder.DeviceEntryUnlockTrackerViewBinder
@@ -39,7 +37,6 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
 import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
@@ -94,7 +91,6 @@
     private val configuration: ConfigurationState,
     private val context: Context,
     private val keyguardIndicationController: KeyguardIndicationController,
-    private val lockIconViewController: Lazy<LegacyLockIconViewController>,
     private val shadeInteractor: ShadeInteractor,
     private val interactionJankMonitor: InteractionJankMonitor,
     private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor,
@@ -171,10 +167,6 @@
     private fun initializeViews() {
         val indicationArea = KeyguardIndicationArea(context, null)
         keyguardIndicationController.setIndicationArea(indicationArea)
-
-        if (!DeviceEntryUdfpsRefactor.isEnabled) {
-            lockIconViewController.get().setLockIconView(LockIconView(context, null))
-        }
     }
 
     private fun bindKeyguardRootView() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d28b08f..fbc76c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -139,7 +139,6 @@
 import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dreams.ui.viewmodel.DreamViewModel;
 import com.android.systemui.dump.DumpManager;
@@ -3569,9 +3568,7 @@
         }
 
         // Ensure that keyguard becomes visible if the going away animation is canceled
-        if (showKeyguard && !KeyguardWmStateRefactor.isEnabled()
-                && (MigrateClocksToBlueprint.isEnabled()
-                    || DeviceEntryUdfpsRefactor.isEnabled())) {
+        if (showKeyguard && !KeyguardWmStateRefactor.isEnabled()) {
             mKeyguardInteractor.showKeyguard();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 690ae71..b7d0d45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -24,7 +24,7 @@
 import android.os.Trace
 import android.util.Log
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.shared.model.KeyguardState
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
index 9626077..03cf1a4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -23,15 +23,12 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
-import com.android.systemui.keyguard.data.repository.BiometricType
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -41,7 +38,6 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
 
 /**
  * Encapsulates business logic for device entry events that impact the side fingerprint sensor
@@ -51,7 +47,6 @@
 class DeviceEntrySideFpsOverlayInteractor
 @Inject
 constructor(
-    @Application private val applicationScope: CoroutineScope,
     @Application private val context: Context,
     deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     private val sceneInteractor: SceneInteractor,
@@ -60,18 +55,6 @@
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
 ) {
 
-    init {
-        if (!DeviceEntryUdfpsRefactor.isEnabled) {
-            applicationScope.launch {
-                deviceEntryFingerprintAuthRepository.availableFpSensorType.collect { sensorType ->
-                    if (sensorType == BiometricType.SIDE_FINGERPRINT) {
-                        alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, TAG)
-                    }
-                }
-            }
-        }
-    }
-
     private val isSideFpsIndicatorOnPrimaryBouncerEnabled: Boolean
         get() = context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
 
@@ -90,7 +73,7 @@
                 primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(),
                 // Bouncer scene visibility changes.
                 isBouncerSceneActive,
-                deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it }
+                deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it },
             )
             .map {
                 isBouncerActive() &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 4cf9ec8..9896365 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -19,7 +19,7 @@
 import android.animation.ValueAnimator
 import android.util.Log
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 9a0a858..7b75765 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -20,7 +20,7 @@
 import android.annotation.SuppressLint
 import android.app.DreamManager
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 6b6a3dce..a6f0db5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 58c8a04..606a7a9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 6d1d9cb..4d37276 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -19,7 +19,7 @@
 import android.animation.ValueAnimator
 import android.util.MathUtils
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
 import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 2c3b481..26bf26b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -22,7 +22,7 @@
 import android.content.Context
 import android.content.Intent
 import android.util.Log
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.logging.KeyguardQuickAffordancesLogger
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt
index fe5f632..23b7b66 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt
@@ -18,7 +18,7 @@
 
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.AuthKeyguardMessageArea
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerMessageAreaViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
index fb97191..6ef9863 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
@@ -21,8 +21,7 @@
 import android.view.View
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
@@ -34,13 +33,7 @@
 
     /** Updates UI for the UDFPS icon on the alternate bouncer. */
     @JvmStatic
-    fun bind(
-        view: DeviceEntryIconView,
-        viewModel: AlternateBouncerUdfpsIconViewModel,
-    ) {
-        if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) {
-            return
-        }
+    fun bind(view: DeviceEntryIconView, viewModel: AlternateBouncerUdfpsIconViewModel) {
         val fgIconView = view.iconView
         val bgView = view.bgView
 
@@ -66,7 +59,7 @@
                 viewModel.fgViewModel.collect { fgViewModel ->
                     fgIconView.setImageState(
                         view.getIconState(fgViewModel.type, fgViewModel.useAodVariant),
-                        /* merge */ false
+                        /* merge */ false,
                     )
                     fgIconView.imageTintList = ColorStateList.valueOf(fgViewModel.tint)
                     fgIconView.setPadding(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
index 7696273..7a36899 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -29,11 +29,10 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder
 import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay
 import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel
@@ -95,7 +94,7 @@
     private var alternateBouncerView: ConstraintLayout? = null
 
     override fun start() {
-        if (!DeviceEntryUdfpsRefactor.isEnabled || SceneContainerFlag.isEnabled) {
+        if (SceneContainerFlag.isEnabled) {
             return
         }
 
@@ -182,14 +181,7 @@
     }
 
     /** Binds the view to the view-model, continuing to update the former based on the latter. */
-    fun bind(
-        view: ConstraintLayout,
-        alternateBouncerDependencies: AlternateBouncerDependencies,
-    ) {
-        if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) {
-            return
-        }
-
+    fun bind(view: ConstraintLayout, alternateBouncerDependencies: AlternateBouncerDependencies) {
         optionallyAddUdfpsViews(
             view = view,
             logger = alternateBouncerDependencies.logger,
@@ -287,10 +279,7 @@
                                         )
                                 }
                             view.addView(udfpsView)
-                            AlternateBouncerUdfpsViewBinder.bind(
-                                udfpsView,
-                                udfpsIconViewModel,
-                            )
+                            AlternateBouncerUdfpsViewBinder.bind(udfpsView, udfpsIconViewModel)
                         }
 
                         val constraintSet = ConstraintSet().apply { clone(view) }
@@ -310,17 +299,17 @@
                                 ConstraintSet.START,
                                 ConstraintSet.PARENT_ID,
                                 ConstraintSet.START,
-                                iconLocation.left
+                                iconLocation.left,
                             )
 
                             // udfpsA11yOverlayView:
                             constrainWidth(
                                 udfpsA11yOverlayViewId,
-                                ViewGroup.LayoutParams.MATCH_PARENT
+                                ViewGroup.LayoutParams.MATCH_PARENT,
                             )
                             constrainHeight(
                                 udfpsA11yOverlayViewId,
-                                ViewGroup.LayoutParams.MATCH_PARENT
+                                ViewGroup.LayoutParams.MATCH_PARENT,
                             )
                         }
                         constraintSet.applyTo(view)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index b951b73..6c104a0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -28,9 +28,8 @@
 import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.common.ui.view.LongPressHandlingView
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
@@ -68,7 +67,6 @@
         vibratorHelper: VibratorHelper,
         overrideColor: Color? = null,
     ): DisposableHandle {
-        DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()
         val disposables = DisposableHandles()
         val longPressHandlingView = view.longPressHandlingView
         val fgIconView = view.iconView
@@ -79,7 +77,7 @@
                     view: View,
                     x: Int,
                     y: Int,
-                    isA11yAction: Boolean
+                    isA11yAction: Boolean,
                 ) {
                     if (
                         !isA11yAction && falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)
@@ -87,14 +85,11 @@
                         Log.d(
                             TAG,
                             "Long press rejected because it is not a11yAction " +
-                                "and it is a falseLongTap"
+                                "and it is a falseLongTap",
                         )
                         return
                     }
-                    vibratorHelper.performHapticFeedback(
-                        view,
-                        HapticFeedbackConstants.CONFIRM,
-                    )
+                    vibratorHelper.performHapticFeedback(view, HapticFeedbackConstants.CONFIRM)
                     applicationScope.launch {
                         view.clearFocus()
                         view.clearAccessibilityFocus()
@@ -192,7 +187,7 @@
                         fgViewModel.viewModel.collect { viewModel ->
                             fgIconView.setImageState(
                                 view.getIconState(viewModel.type, viewModel.useAodVariant),
-                                /* merge */ false
+                                /* merge */ false,
                             )
                             if (viewModel.type.contentDescriptionResId != -1) {
                                 fgIconView.contentDescription =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index 00aa44f..5bad016 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -22,7 +22,8 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition
@@ -32,7 +33,6 @@
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.res.R
 import com.android.systemui.shared.R as sharedR
 import com.android.systemui.util.kotlin.pairwise
 
@@ -128,7 +128,7 @@
     ) {
         val currentClock = viewModel.currentClock.value
         if (!DEBUG || currentClock == null) return
-        val smallClockViewId = R.id.lockscreen_clock_view
+        val smallClockViewId = customR.id.lockscreen_clock_view
         val largeClockViewId = currentClock.largeClock.layout.views[0].id
         val smartspaceDateId = sharedR.id.date_smartspace_view
         Log.i(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 660a650..3bdf7da 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -36,7 +36,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.settingslib.Utils
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.animation.Expandable
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
index ba94f45..8b947a3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
@@ -22,7 +22,7 @@
 import android.widget.TextView
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
index 76d3389..2fd9818 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.common.ui.view.LongPressHandlingView
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardTouchHandlingViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 57cb10f..210f4cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -33,9 +33,9 @@
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.policy.SystemBarUtils
-import com.android.systemui.customization.R as customizationR
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
 import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer
 import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection.Companion.getDimen
@@ -50,6 +50,8 @@
 
 /** Binder for the small clock view, large clock view. */
 object KeyguardPreviewClockViewBinder {
+    val lockId = View.generateViewId()
+
     @JvmStatic
     fun bind(
         largeClockHostView: View,
@@ -120,36 +122,36 @@
 
     private fun applyClockDefaultConstraints(context: Context, constraints: ConstraintSet) {
         constraints.apply {
-            constrainWidth(R.id.lockscreen_clock_view_large, ConstraintSet.WRAP_CONTENT)
+            constrainWidth(customR.id.lockscreen_clock_view_large, ConstraintSet.WRAP_CONTENT)
             // The following two lines make lockscreen_clock_view_large is constrained to available
             // height when it goes beyond constraints; otherwise, it use WRAP_CONTENT
-            constrainHeight(R.id.lockscreen_clock_view_large, WRAP_CONTENT)
-            constrainMaxHeight(R.id.lockscreen_clock_view_large, 0)
+            constrainHeight(customR.id.lockscreen_clock_view_large, WRAP_CONTENT)
+            constrainMaxHeight(customR.id.lockscreen_clock_view_large, 0)
             val largeClockTopMargin =
                 SystemBarUtils.getStatusBarHeight(context) +
                     context.resources.getDimensionPixelSize(
-                        customizationR.dimen.small_clock_padding_top
+                        customR.dimen.small_clock_padding_top
                     ) +
                     context.resources.getDimensionPixelSize(
                         R.dimen.keyguard_smartspace_top_offset
                     ) +
                     getDimen(context, DATE_WEATHER_VIEW_HEIGHT) +
                     getDimen(context, ENHANCED_SMARTSPACE_HEIGHT)
-            connect(R.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin)
-            connect(R.id.lockscreen_clock_view_large, START, PARENT_ID, START)
+            connect(customR.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin)
+            connect(customR.id.lockscreen_clock_view_large, START, PARENT_ID, START)
             connect(
-                R.id.lockscreen_clock_view_large,
+                customR.id.lockscreen_clock_view_large,
                 ConstraintSet.END,
                 PARENT_ID,
                 ConstraintSet.END,
             )
 
-            // In preview, we'll show UDFPS icon for UDFPS devices
-            // and nothing for non-UDFPS devices,
-            // but we need position of device entry icon to constrain clock
-            if (getConstraint(R.id.lock_icon_view) != null) {
-                connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.lock_icon_view, TOP)
-            } else {
+
+            // In preview, we'll show UDFPS icon for UDFPS devices and nothing for non-UDFPS
+            // devices, but we need position of device entry icon to constrain clock
+            if (getConstraint(lockId) != null) {
+                connect(customR.id.lockscreen_clock_view_large, BOTTOM, lockId, TOP)
+           } else {
                 // Copied calculation codes from applyConstraints in DefaultDeviceEntrySection
                 val bottomPaddingPx =
                     context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
@@ -159,7 +161,7 @@
                 val lockIconRadiusPx = (defaultDensity * 36).toInt()
                 val clockBottomMargin = bottomPaddingPx + 2 * lockIconRadiusPx
                 connect(
-                    R.id.lockscreen_clock_view_large,
+                    customR.id.lockscreen_clock_view_large,
                     BOTTOM,
                     PARENT_ID,
                     BOTTOM,
@@ -167,23 +169,23 @@
                 )
             }
 
-            constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT)
+            constrainWidth(customR.id.lockscreen_clock_view, WRAP_CONTENT)
             constrainHeight(
-                R.id.lockscreen_clock_view,
-                context.resources.getDimensionPixelSize(customizationR.dimen.small_clock_height),
+                customR.id.lockscreen_clock_view,
+                context.resources.getDimensionPixelSize(customR.dimen.small_clock_height),
             )
             connect(
-                R.id.lockscreen_clock_view,
+                customR.id.lockscreen_clock_view,
                 START,
                 PARENT_ID,
                 START,
-                context.resources.getDimensionPixelSize(customizationR.dimen.clock_padding_start) +
+                context.resources.getDimensionPixelSize(customR.dimen.clock_padding_start) +
                     context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
             )
             val smallClockTopMargin =
                 context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
                     Utils.getStatusBarHeaderHeightKeyguard(context)
-            connect(R.id.lockscreen_clock_view, TOP, PARENT_ID, TOP, smallClockTopMargin)
+            connect(customR.id.lockscreen_clock_view, TOP, PARENT_ID, TOP, smallClockTopMargin)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
index 4b75b80..baa6812 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
index 27dd18d..cfd6481 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
@@ -30,7 +30,7 @@
 import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.logging.KeyguardQuickAffordancesLogger
 import com.android.settingslib.Utils
 import com.android.systemui.animation.Expandable
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index ee2ee52..89bca0c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -39,7 +39,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
 import com.android.keyguard.AuthInteractionProperties
@@ -52,8 +52,8 @@
 import com.android.systemui.common.ui.view.onApplyWindowInsets
 import com.android.systemui.common.ui.view.onLayoutChanged
 import com.android.systemui.common.ui.view.onTouchListener
+import com.android.systemui.customization.R as customR
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
@@ -180,16 +180,12 @@
                         }
                     }
 
-                    if (
-                        KeyguardBottomAreaRefactor.isEnabled || DeviceEntryUdfpsRefactor.isEnabled
-                    ) {
-                        launch("$TAG#alpha") {
-                            viewModel.alpha(viewState).collect { alpha ->
-                                view.alpha = alpha
-                                if (KeyguardBottomAreaRefactor.isEnabled) {
-                                    childViews[statusViewId]?.alpha = alpha
-                                    childViews[burnInLayerId]?.alpha = alpha
-                                }
+                    launch("$TAG#alpha") {
+                        viewModel.alpha(viewState).collect { alpha ->
+                            view.alpha = alpha
+                            if (KeyguardBottomAreaRefactor.isEnabled) {
+                                childViews[statusViewId]?.alpha = alpha
+                                childViews[burnInLayerId]?.alpha = alpha
                             }
                         }
                     }
@@ -223,7 +219,6 @@
                                                 indicationArea,
                                                 startButton,
                                                 endButton,
-                                                lockIcon,
                                                 deviceEntryIcon -> {
                                                     // Do not move these views
                                                 }
@@ -622,12 +617,11 @@
     private val statusViewId = R.id.keyguard_status_view
     private val burnInLayerId = R.id.burn_in_layer
     private val aodNotificationIconContainerId = R.id.aod_notification_icon_container
-    private val largeClockId = R.id.lockscreen_clock_view_large
-    private val smallClockId = R.id.lockscreen_clock_view
+    private val largeClockId = customR.id.lockscreen_clock_view_large
+    private val smallClockId = customR.id.lockscreen_clock_view
     private val indicationArea = R.id.keyguard_indication_area
     private val startButton = R.id.start_button
     private val endButton = R.id.end_button
-    private val lockIcon = R.id.lock_icon_view
     private val deviceEntryIcon = R.id.device_entry_icon_view
     private val nsslPlaceholderId = R.id.nssl_placeholder
     private val authInteractionProperties = AuthInteractionProperties()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
index 4150ceb..79360370 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.common.ui.binder.TextViewBinder
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index 8b74f5d..de4a1b0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -21,7 +21,7 @@
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt
index fd27dc3..3934917 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSurfaceBehindViewModel
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
index b2ee689..2df17c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
@@ -18,7 +18,7 @@
 
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.LightRevealScrim
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt
index ae46dd3..b1ce47e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
 import com.android.systemui.keyguard.ui.viewmodel.WindowManagerLockscreenVisibilityViewModel
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index cef9a4e..08d35a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -17,7 +17,6 @@
 
 package com.android.systemui.keyguard.ui.preview
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.app.WallpaperColors
 import android.content.BroadcastReceiver
 import android.content.Context
@@ -57,6 +56,7 @@
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder
 import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -151,10 +151,7 @@
     private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
     private val height: Int = bundle.getInt(KEY_VIEW_HEIGHT)
     private val shouldHighlightSelectedAffordance: Boolean =
-        bundle.getBoolean(
-            KeyguardPreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES,
-            false,
-        )
+        bundle.getBoolean(KeyguardPreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES, false)
 
     private val displayId = bundle.getInt(KEY_DISPLAY_ID, DEFAULT_DISPLAY)
     private val display: Display? = displayManager.getDisplay(displayId)
@@ -188,24 +185,26 @@
     private var themeStyle: Style? = null
 
     init {
-        coroutineScope = CoroutineScope(applicationScope.coroutineContext + Job() + createCoroutineTracingContext("KeyguardPreviewRenderer"))
+        coroutineScope =
+            CoroutineScope(
+                applicationScope.coroutineContext +
+                    Job() +
+                    newTracingContext("KeyguardPreviewRenderer")
+            )
         disposables += DisposableHandle { coroutineScope.cancel() }
         clockController.setFallbackWeatherData(WeatherData.getPlaceholderWeatherData())
 
         if (KeyguardBottomAreaRefactor.isEnabled) {
             quickAffordancesCombinedViewModel.enablePreviewMode(
                 initiallySelectedSlotId =
-                    bundle.getString(
-                        KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID,
-                    ) ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                    bundle.getString(KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID)
+                        ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
                 shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
             )
         } else {
             bottomAreaViewModel.enablePreviewMode(
                 initiallySelectedSlotId =
-                    bundle.getString(
-                        KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID,
-                    ),
+                    bundle.getString(KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID),
                 shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
             )
         }
@@ -218,7 +217,7 @@
                     context,
                     displayManager.getDisplay(DEFAULT_DISPLAY),
                     if (hostToken == null) null else InputTransferToken(hostToken),
-                    "KeyguardPreviewRenderer"
+                    "KeyguardPreviewRenderer",
                 )
             disposables += DisposableHandle { host.release() }
         }
@@ -247,12 +246,12 @@
             rootView.measure(
                 View.MeasureSpec.makeMeasureSpec(
                     displayInfo?.logicalWidth ?: windowManager.currentWindowMetrics.bounds.width(),
-                    View.MeasureSpec.EXACTLY
+                    View.MeasureSpec.EXACTLY,
                 ),
                 View.MeasureSpec.makeMeasureSpec(
                     displayInfo?.logicalHeight
                         ?: windowManager.currentWindowMetrics.bounds.height(),
-                    View.MeasureSpec.EXACTLY
+                    View.MeasureSpec.EXACTLY,
                 ),
             )
             rootView.layout(0, 0, rootView.measuredWidth, rootView.measuredHeight)
@@ -278,9 +277,7 @@
         }
     }
 
-    fun onStartCustomizingQuickAffordances(
-        initiallySelectedSlotId: String?,
-    ) {
+    fun onStartCustomizingQuickAffordances(initiallySelectedSlotId: String?) {
         quickAffordancesCombinedViewModel.enablePreviewMode(
             initiallySelectedSlotId = initiallySelectedSlotId,
             shouldHighlightSelectedAffordance = true,
@@ -379,15 +376,9 @@
     @Deprecated("Deprecated as part of b/278057014")
     private fun setUpBottomArea(parentView: ViewGroup) {
         val bottomAreaView =
-            LayoutInflater.from(context)
-                .inflate(
-                    R.layout.keyguard_bottom_area,
-                    parentView,
-                    false,
-                ) as KeyguardBottomAreaView
-        bottomAreaView.init(
-            viewModel = bottomAreaViewModel,
-        )
+            LayoutInflater.from(context).inflate(R.layout.keyguard_bottom_area, parentView, false)
+                as KeyguardBottomAreaView
+        bottomAreaView.init(viewModel = bottomAreaViewModel)
         parentView.addView(
             bottomAreaView,
             FrameLayout.LayoutParams(
@@ -433,7 +424,7 @@
 
         setUpUdfps(
             previewContext,
-            if (MigrateClocksToBlueprint.isEnabled) keyguardRootView else rootView
+            if (MigrateClocksToBlueprint.isEnabled) keyguardRootView else rootView,
         )
 
         if (KeyguardBottomAreaRefactor.isEnabled) {
@@ -466,7 +457,7 @@
                 previewContext,
                 it,
                 previewInSplitShade(),
-                smartspaceViewModel
+                smartspaceViewModel,
             )
         }
         setupCommunalTutorialIndicator(keyguardRootView)
@@ -515,23 +506,20 @@
 
         val finger =
             LayoutInflater.from(previewContext)
-                .inflate(
-                    R.layout.udfps_keyguard_preview,
-                    parentView,
-                    false,
-                ) as View
+                .inflate(R.layout.udfps_keyguard_preview, parentView, false) as View
 
         // Place the UDFPS view in the proper sensor location
         if (MigrateClocksToBlueprint.isEnabled) {
-            finger.id = R.id.lock_icon_view
+            val lockId = KeyguardPreviewClockViewBinder.lockId
+            finger.id = lockId
             parentView.addView(finger)
             val cs = ConstraintSet()
             cs.clone(parentView as ConstraintLayout)
             cs.apply {
-                constrainWidth(R.id.lock_icon_view, sensorBounds.width())
-                constrainHeight(R.id.lock_icon_view, sensorBounds.height())
-                connect(R.id.lock_icon_view, TOP, PARENT_ID, TOP, sensorBounds.top)
-                connect(R.id.lock_icon_view, START, PARENT_ID, START, sensorBounds.left)
+                constrainWidth(lockId, sensorBounds.width())
+                constrainHeight(lockId, sensorBounds.height())
+                connect(lockId, TOP, PARENT_ID, TOP, sensorBounds.top)
+                connect(lockId, START, PARENT_ID, START, sensorBounds.left)
             }
             cs.applyTo(parentView)
         } else {
@@ -541,7 +529,7 @@
                 sensorBounds.left,
                 sensorBounds.top,
                 sensorBounds.right,
-                sensorBounds.bottom
+                sensorBounds.bottom,
             )
             parentView.addView(finger, fingerprintLayoutParams)
         }
@@ -565,7 +553,7 @@
                     FrameLayout.LayoutParams.WRAP_CONTENT,
                     resources.getDimensionPixelSize(
                         com.android.systemui.customization.R.dimen.small_clock_height
-                    )
+                    ),
                 )
             layoutParams.topMargin =
                 SystemBarUtils.getStatusBarHeight(previewContext) +
@@ -579,7 +567,7 @@
                 ),
                 /* top = */ 0,
                 /* end = */ 0,
-                /* bottom = */ 0
+                /* bottom = */ 0,
             )
             smallClockHostView.clipChildren = false
             parentView.addView(smallClockHostView)
@@ -703,9 +691,7 @@
     private suspend fun fetchThemeStyleFromSetting(): Style {
         val overlayPackageJson =
             withContext(backgroundDispatcher) {
-                secureSettings.getString(
-                    Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
-                )
+                secureSettings.getString(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES)
             }
         return if (!overlayPackageJson.isNullOrEmpty()) {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index 075a1d2..9355200 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -25,7 +25,7 @@
 import android.util.ArrayMap
 import android.util.Log
 import androidx.annotation.VisibleForTesting
-import com.android.app.tracing.coroutines.runBlocking
+import com.android.app.tracing.coroutines.runBlockingTraced as runBlocking
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index d745522..ee4f41d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -30,7 +30,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import androidx.constraintlayout.widget.ConstraintSet.VISIBLE
 import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
-import com.android.systemui.customization.R as custR
+import com.android.systemui.customization.R as customR
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
@@ -153,7 +153,7 @@
                 R.id.weather_clock_bc_smartspace_bottom,
                 Barrier.BOTTOM,
                 getDimen(ENHANCED_SMARTSPACE_HEIGHT),
-                (custR.id.weather_clock_time),
+                (customR.id.weather_clock_time),
             )
             if (
                 rootViewModel.isNotifIconContainerVisible.value.value &&
@@ -184,40 +184,40 @@
             if (keyguardClockViewModel.clockShouldBeCentered.value) PARENT_ID
             else R.id.split_shade_guideline
         constraints.apply {
-            connect(R.id.lockscreen_clock_view_large, START, PARENT_ID, START)
-            connect(R.id.lockscreen_clock_view_large, END, guideline, END)
-            connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.device_entry_icon_view, TOP)
+            connect(customR.id.lockscreen_clock_view_large, START, PARENT_ID, START)
+            connect(customR.id.lockscreen_clock_view_large, END, guideline, END)
+            connect(customR.id.lockscreen_clock_view_large, BOTTOM, R.id.device_entry_icon_view, TOP)
             val largeClockTopMargin =
                 keyguardClockViewModel.getLargeClockTopMargin() +
                     getDimen(DATE_WEATHER_VIEW_HEIGHT) +
                     getDimen(ENHANCED_SMARTSPACE_HEIGHT)
-            connect(R.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin)
-            constrainWidth(R.id.lockscreen_clock_view_large, WRAP_CONTENT)
+            connect(customR.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin)
+            constrainWidth(customR.id.lockscreen_clock_view_large, WRAP_CONTENT)
 
             // The following two lines make lockscreen_clock_view_large is constrained to available
             // height when it goes beyond constraints; otherwise, it use WRAP_CONTENT
-            constrainHeight(R.id.lockscreen_clock_view_large, WRAP_CONTENT)
-            constrainMaxHeight(R.id.lockscreen_clock_view_large, 0)
-            constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT)
+            constrainHeight(customR.id.lockscreen_clock_view_large, WRAP_CONTENT)
+            constrainMaxHeight(customR.id.lockscreen_clock_view_large, 0)
+            constrainWidth(customR.id.lockscreen_clock_view, WRAP_CONTENT)
             constrainHeight(
-                R.id.lockscreen_clock_view,
-                context.resources.getDimensionPixelSize(custR.dimen.small_clock_height),
+                customR.id.lockscreen_clock_view,
+                context.resources.getDimensionPixelSize(customR.dimen.small_clock_height),
             )
             connect(
-                R.id.lockscreen_clock_view,
+                customR.id.lockscreen_clock_view,
                 START,
                 PARENT_ID,
                 START,
-                context.resources.getDimensionPixelSize(custR.dimen.clock_padding_start) +
+                context.resources.getDimensionPixelSize(customR.dimen.clock_padding_start) +
                     context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
             )
             val smallClockTopMargin = keyguardClockViewModel.getSmallClockTopMargin()
             create(R.id.small_clock_guideline_top, ConstraintSet.HORIZONTAL_GUIDELINE)
             setGuidelineBegin(R.id.small_clock_guideline_top, smallClockTopMargin)
-            connect(R.id.lockscreen_clock_view, TOP, R.id.small_clock_guideline_top, BOTTOM)
+            connect(customR.id.lockscreen_clock_view, TOP, R.id.small_clock_guideline_top, BOTTOM)
 
             // Explicitly clear pivot to force recalculate pivot instead of using legacy value
-            setTransformPivot(R.id.lockscreen_clock_view_large, Float.NaN, Float.NaN)
+            setTransformPivot(customR.id.lockscreen_clock_view_large, Float.NaN, Float.NaN)
 
             val smallClockBottom =
                 keyguardClockViewModel.getSmallClockTopMargin() +
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 782d37b..8d2bfb5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -27,11 +27,8 @@
 import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
-import com.android.keyguard.LockIconView
-import com.android.keyguard.LockIconViewController
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
@@ -66,7 +63,6 @@
     private val context: Context,
     private val notificationPanelView: NotificationPanelView,
     private val featureFlags: FeatureFlags,
-    private val lockIconViewController: Lazy<LockIconViewController>,
     private val deviceEntryIconViewModel: Lazy<DeviceEntryIconViewModel>,
     private val deviceEntryForegroundViewModel: Lazy<DeviceEntryForegroundViewModel>,
     private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
@@ -78,70 +74,44 @@
     private var disposableHandle: DisposableHandle? = null
 
     override fun addViews(constraintLayout: ConstraintLayout) {
-        if (
-            !KeyguardBottomAreaRefactor.isEnabled &&
-                !MigrateClocksToBlueprint.isEnabled &&
-                !DeviceEntryUdfpsRefactor.isEnabled
-        ) {
+        if (!KeyguardBottomAreaRefactor.isEnabled && !MigrateClocksToBlueprint.isEnabled) {
             return
         }
 
-        notificationPanelView.findViewById<View>(R.id.lock_icon_view).let {
-            notificationPanelView.removeView(it)
-        }
-
         val view =
-            if (DeviceEntryUdfpsRefactor.isEnabled) {
-                DeviceEntryIconView(
-                        context,
-                        null,
-                        logger =
-                            LongPressHandlingViewLogger(
-                                logBuffer = logBuffer,
-                                TAG
-                            )
-                    )
-                    .apply { id = deviceEntryIconViewId }
-            } else {
-                // KeyguardBottomAreaRefactor.isEnabled or MigrateClocksToBlueprint.isEnabled
-                LockIconView(context, null).apply { id = R.id.lock_icon_view }
-            }
+            DeviceEntryIconView(
+                    context,
+                    null,
+                    logger = LongPressHandlingViewLogger(logBuffer = logBuffer, TAG),
+                )
+                .apply { id = deviceEntryIconViewId }
+
         constraintLayout.addView(view)
     }
 
     override fun bindData(constraintLayout: ConstraintLayout) {
-        if (DeviceEntryUdfpsRefactor.isEnabled) {
-            constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
-                disposableHandle?.dispose()
-                disposableHandle =
-                    DeviceEntryIconViewBinder.bind(
-                        applicationScope,
-                        it,
-                        deviceEntryIconViewModel.get(),
-                        deviceEntryForegroundViewModel.get(),
-                        deviceEntryBackgroundViewModel.get(),
-                        falsingManager.get(),
-                        vibratorHelper.get(),
-                    )
-            }
-        } else {
-            constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
-                lockIconViewController.get().setLockIconView(it)
-            }
+        constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
+            disposableHandle?.dispose()
+            disposableHandle =
+                DeviceEntryIconViewBinder.bind(
+                    applicationScope,
+                    it,
+                    deviceEntryIconViewModel.get(),
+                    deviceEntryForegroundViewModel.get(),
+                    deviceEntryBackgroundViewModel.get(),
+                    falsingManager.get(),
+                    vibratorHelper.get(),
+                )
         }
     }
 
     override fun applyConstraints(constraintSet: ConstraintSet) {
-        val isUdfpsSupported =
-            if (DeviceEntryUdfpsRefactor.isEnabled) {
-                Log.d(
-                    "DefaultDeviceEntrySection",
-                    "isUdfpsSupported=${deviceEntryIconViewModel.get().isUdfpsSupported.value}"
-                )
-                deviceEntryIconViewModel.get().isUdfpsSupported.value
-            } else {
-                authController.isUdfpsSupported
-            }
+        Log.d(
+            "DefaultDeviceEntrySection",
+            "isUdfpsSupported=${deviceEntryIconViewModel.get().isUdfpsSupported.value}",
+        )
+        val isUdfpsSupported = deviceEntryIconViewModel.get().isUdfpsSupported.value
+
         val scaleFactor: Float = authController.scaleFactor
         val mBottomPaddingPx =
             context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
@@ -160,31 +130,24 @@
         val iconRadiusPx = (defaultDensity * 36).toInt()
 
         if (isUdfpsSupported) {
-            if (DeviceEntryUdfpsRefactor.isEnabled) {
-                deviceEntryIconViewModel.get().udfpsLocation.value?.let { udfpsLocation ->
-                    Log.d(
-                        "DeviceEntrySection",
-                        "udfpsLocation=$udfpsLocation, " +
-                            "scaledLocation=(${udfpsLocation.centerX},${udfpsLocation.centerY}), " +
-                            "unusedAuthController=${authController.udfpsLocation}"
-                    )
-                    centerIcon(
-                        Point(udfpsLocation.centerX.toInt(), udfpsLocation.centerY.toInt()),
-                        udfpsLocation.radius,
-                        constraintSet
-                    )
-                }
-            } else {
-                authController.udfpsLocation?.let { udfpsLocation ->
-                    Log.d("DeviceEntrySection", "udfpsLocation=$udfpsLocation")
-                    centerIcon(udfpsLocation, authController.udfpsRadius, constraintSet)
-                }
+            deviceEntryIconViewModel.get().udfpsLocation.value?.let { udfpsLocation ->
+                Log.d(
+                    "DeviceEntrySection",
+                    "udfpsLocation=$udfpsLocation, " +
+                        "scaledLocation=(${udfpsLocation.centerX},${udfpsLocation.centerY}), " +
+                        "unusedAuthController=${authController.udfpsLocation}",
+                )
+                centerIcon(
+                    Point(udfpsLocation.centerX.toInt(), udfpsLocation.centerY.toInt()),
+                    udfpsLocation.radius,
+                    constraintSet,
+                )
             }
         } else {
             centerIcon(
                 Point(
                     (widthPixels / 2).toInt(),
-                    (heightPixels - ((mBottomPaddingPx + iconRadiusPx) * scaleFactor)).toInt()
+                    (heightPixels - ((mBottomPaddingPx + iconRadiusPx) * scaleFactor)).toInt(),
                 ),
                 iconRadiusPx * scaleFactor,
                 constraintSet,
@@ -193,12 +156,8 @@
     }
 
     override fun removeViews(constraintLayout: ConstraintLayout) {
-        if (DeviceEntryUdfpsRefactor.isEnabled) {
-            constraintLayout.removeView(deviceEntryIconViewId)
-            disposableHandle?.dispose()
-        } else {
-            constraintLayout.removeView(R.id.lock_icon_view)
-        }
+        constraintLayout.removeView(deviceEntryIconViewId)
+        disposableHandle?.dispose()
     }
 
     @VisibleForTesting
@@ -213,12 +172,7 @@
                 )
             }
 
-        val iconId =
-            if (DeviceEntryUdfpsRefactor.isEnabled) {
-                deviceEntryIconViewId
-            } else {
-                R.id.lock_icon_view
-            }
+        val iconId = deviceEntryIconViewId
 
         constraintSet.apply {
             constrainWidth(iconId, sensorRect.right - sensorRect.left)
@@ -228,14 +182,14 @@
                 ConstraintSet.TOP,
                 ConstraintSet.PARENT_ID,
                 ConstraintSet.TOP,
-                sensorRect.top
+                sensorRect.top,
             )
             connect(
                 iconId,
                 ConstraintSet.START,
                 ConstraintSet.PARENT_ID,
                 ConstraintSet.START,
-                sensorRect.left
+                sensorRect.left,
             )
         }
 
@@ -243,8 +197,8 @@
         // Without this logic, the lock icon location changes but the KeyguardBottomAreaView is not
         // updated and visible ui layout jank occurs. This is due to AmbientIndicationContainer
         // being in NPVC and laying out prior to the KeyguardRootView.
-        // Remove when both DeviceEntryUdfpsRefactor and KeyguardBottomAreaRefactor are enabled.
-        if (DeviceEntryUdfpsRefactor.isEnabled && !KeyguardBottomAreaRefactor.isEnabled) {
+        // Remove when KeyguardBottomAreaRefactor is enabled.
+        if (!KeyguardBottomAreaRefactor.isEnabled) {
             with(notificationPanelView) {
                 val isUdfpsSupported = deviceEntryIconViewModel.get().isUdfpsSupported.value
                 val bottomAreaViewRight = findViewById<View>(R.id.keyguard_bottom_area)?.right ?: 0
@@ -256,7 +210,7 @@
                             ambientLeft,
                             sensorRect.bottom,
                             bottomAreaViewRight - ambientLeft,
-                            ambientTop + it.measuredHeight
+                            ambientTop + it.measuredHeight,
                         )
                     } else {
                         // make bottom of ambient indication view the top of the lock icon
@@ -264,7 +218,7 @@
                             ambientLeft,
                             sensorRect.top - it.measuredHeight,
                             bottomAreaViewRight - ambientLeft,
-                            sensorRect.top
+                            sensorRect.top,
                         )
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt
index b33d552..604318a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt
@@ -22,6 +22,7 @@
 import androidx.constraintlayout.widget.Barrier
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.res.R
@@ -67,7 +68,7 @@
             connect(
                 R.id.keyguard_slice_view,
                 ConstraintSet.TOP,
-                R.id.lockscreen_clock_view,
+                customR.id.lockscreen_clock_view,
                 ConstraintSet.BOTTOM
             )
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
index edcf97a..620cc13 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
@@ -55,11 +55,7 @@
                 R.id.nssl_placeholder_barrier_bottom,
                 Barrier.TOP,
                 0,
-                *intArrayOf(
-                    R.id.device_entry_icon_view,
-                    R.id.lock_icon_view,
-                    R.id.ambient_indication_container
-                )
+                *intArrayOf(R.id.device_entry_icon_view, R.id.ambient_indication_container),
             )
             connect(placeHolderId, BOTTOM, R.id.nssl_placeholder_barrier_bottom, TOP)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 99160f8..6ddcae3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -23,6 +23,7 @@
 import androidx.constraintlayout.widget.Barrier
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.customization.R as customR
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
@@ -157,7 +158,7 @@
                 connect(
                     sharedR.id.date_smartspace_view,
                     ConstraintSet.TOP,
-                    R.id.lockscreen_clock_view,
+                    customR.id.lockscreen_clock_view,
                     ConstraintSet.BOTTOM
                 )
                 connect(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 4d914c7..c11005d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -29,6 +29,7 @@
 import android.view.ViewGroup
 import android.view.ViewTreeObserver.OnPreDrawListener
 import com.android.app.animation.Interpolators
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
 import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_DOWN_MILLIS
@@ -242,11 +243,11 @@
                 }
                     ?: run {
                         Log.e(TAG, "No large clock set, falling back")
-                        addTarget(R.id.lockscreen_clock_view_large)
+                        addTarget(customR.id.lockscreen_clock_view_large)
                     }
             } else {
                 if (DEBUG) Log.i(TAG, "Adding small clock")
-                addTarget(R.id.lockscreen_clock_view)
+                addTarget(customR.id.lockscreen_clock_view)
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index 0d55709..f765e60 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -19,6 +19,7 @@
 
 import androidx.annotation.VisibleForTesting
 import com.android.app.tracing.FlowTracing.traceEmissionCount
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
@@ -141,6 +142,7 @@
                 fadeInAlpha,
                 fadeOutAlpha,
             )
+            .flowName("transitionAlpha")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
index df1394b..7c02f28 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
@@ -19,7 +19,7 @@
 import androidx.compose.runtime.State
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.snapshots.StateFactoryMarker
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.tracing.coroutines.traceCoroutine
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.coroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index 5559698..a86bfb1 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -17,7 +17,6 @@
 
 package com.android.systemui.lifecycle
 
-import android.os.Trace
 import android.view.View
 import android.view.ViewTreeObserver
 import androidx.annotation.MainThread
@@ -25,11 +24,8 @@
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LifecycleRegistry
 import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
-import com.android.app.tracing.coroutines.traceCoroutine
-import com.android.systemui.Flags.coroutineTracing
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.util.Assert
-import com.android.systemui.util.Compile
 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
 import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
 import kotlin.coroutines.CoroutineContext
@@ -83,25 +79,13 @@
     // default behavior. Instead, we want it to run on the view's UI thread since the user will
     // presumably want to call view methods that require being called from said UI thread.
     val lifecycleCoroutineContext = MAIN_DISPATCHER_SINGLETON + coroutineContext
-    val traceName =
-        if (Compile.IS_DEBUG && coroutineTracing()) {
-            inferTraceSectionName()
-        } else {
-            DEFAULT_TRACE_NAME
-        }
     var lifecycleOwner: ViewLifecycleOwner? = null
     val onAttachListener =
         object : View.OnAttachStateChangeListener {
             override fun onViewAttachedToWindow(v: View) {
                 Assert.isMainThread()
                 lifecycleOwner?.onDestroy()
-                lifecycleOwner =
-                    createLifecycleOwnerAndRun(
-                        traceName,
-                        view,
-                        lifecycleCoroutineContext,
-                        block,
-                    )
+                lifecycleOwner = createLifecycleOwnerAndRun(view, lifecycleCoroutineContext, block)
             }
 
             override fun onViewDetachedFromWindow(v: View) {
@@ -112,13 +96,7 @@
 
     addOnAttachStateChangeListener(onAttachListener)
     if (view.isAttachedToWindow) {
-        lifecycleOwner =
-            createLifecycleOwnerAndRun(
-                traceName,
-                view,
-                lifecycleCoroutineContext,
-                block,
-            )
+        lifecycleOwner = createLifecycleOwnerAndRun(view, lifecycleCoroutineContext, block)
     }
 
     return DisposableHandle {
@@ -131,14 +109,15 @@
 }
 
 private fun createLifecycleOwnerAndRun(
-    nameForTrace: String,
     view: View,
     coroutineContext: CoroutineContext,
     block: suspend LifecycleOwner.(View) -> Unit,
 ): ViewLifecycleOwner {
     return ViewLifecycleOwner(view).apply {
         onCreate()
-        lifecycleScope.launch(coroutineContext) { traceCoroutine(nameForTrace) { block(view) } }
+        // TODO(b/370595466): Refactor to support installing CoroutineTracingContext on the
+        //                    top-level CoroutineScope used as the lifecycleScope
+        lifecycleScope.launch(coroutineContext) { block(view) }
     }
 }
 
@@ -167,9 +146,7 @@
  * └───────────────┴───────────────────┴──────────────┴─────────────────┘
  * ```
  */
-class ViewLifecycleOwner(
-    private val view: View,
-) : LifecycleOwner {
+class ViewLifecycleOwner(private val view: View) : LifecycleOwner {
 
     private val windowVisibleListener =
         ViewTreeObserver.OnWindowVisibilityChangeListener { updateState() }
@@ -205,28 +182,6 @@
     }
 }
 
-private fun isFrameInteresting(frame: StackWalker.StackFrame): Boolean =
-    frame.className != CURRENT_CLASS_NAME && frame.className != JAVA_ADAPTER_CLASS_NAME
-
-/** Get a name for the trace section include the name of the call site. */
-private fun inferTraceSectionName(): String {
-    try {
-        Trace.traceBegin(Trace.TRACE_TAG_APP, "RepeatWhenAttachedKt#inferTraceSectionName")
-        val interestingFrame =
-            StackWalker.getInstance().walk { stream ->
-                stream.filter(::isFrameInteresting).limit(5).findFirst()
-            }
-        return if (interestingFrame.isPresent) {
-            val f = interestingFrame.get()
-            "${f.className}#${f.methodName}:${f.lineNumber} [$DEFAULT_TRACE_NAME]"
-        } else {
-            DEFAULT_TRACE_NAME
-        }
-    } finally {
-        Trace.traceEnd(Trace.TRACE_TAG_APP)
-    }
-}
-
 /**
  * Runs the given [block] in a new coroutine when `this` [View]'s Window's [WindowLifecycleState] is
  * at least at [state] (or immediately after calling this function if the window is already at least
@@ -368,8 +323,7 @@
  * an extension function, and plumbing dagger-injected instances for static usage has little
  * benefit.
  */
-private val MAIN_DISPATCHER_SINGLETON =
-    Dispatchers.Main + createCoroutineTracingContext("RepeatWhenAttached")
+private val MAIN_DISPATCHER_SINGLETON = Dispatchers.Main + newTracingContext("RepeatWhenAttached")
 private const val DEFAULT_TRACE_NAME = "repeatWhenAttached"
 private const val CURRENT_CLASS_NAME = "com.android.systemui.lifecycle.RepeatWhenAttachedKt"
 private const val JAVA_ADAPTER_CLASS_NAME = "com.android.systemui.util.kotlin.JavaAdapterKt"
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index 544dbdd..f40ad06 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -16,13 +16,13 @@
 
 package com.android.systemui.mediaprojection.appselector
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.app.Activity
 import android.content.ComponentName
 import android.content.Context
 import android.os.UserHandle
 import androidx.lifecycle.DefaultLifecycleObserver
 import com.android.launcher3.icons.IconFactory
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader
 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
@@ -134,7 +134,11 @@
         @MediaProjectionAppSelector
         @MediaProjectionAppSelectorScope
         fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope =
-            CoroutineScope(applicationScope.coroutineContext + SupervisorJob() + createCoroutineTracingContext("MediaProjectionAppSelectorScope"))
+            CoroutineScope(
+                applicationScope.coroutineContext +
+                    SupervisorJob() +
+                    newTracingContext("MediaProjectionAppSelectorScope")
+            )
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
index 96386e5..0166176 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.navigationbar.gestural.domain
 
-import com.android.app.tracing.coroutines.flow.flowOn
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -35,6 +34,7 @@
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 3aa9daa..d0f6f79 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -37,7 +37,7 @@
 import android.provider.Settings
 import android.widget.Toast
 import androidx.annotation.VisibleForTesting
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 9c5231d..49b44cb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -23,7 +23,9 @@
 import android.os.Bundle
 import android.util.IndentingPrintWriter
 import android.view.LayoutInflater
+import android.view.MotionEvent
 import android.view.View
+import android.view.ViewConfiguration
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.activity.OnBackPressedDispatcher
@@ -35,6 +37,7 @@
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
 import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.ScrollState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
@@ -43,6 +46,7 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
@@ -83,6 +87,7 @@
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.lifecycle.setSnapshotBinding
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dagger.MediaModule.QS_PANEL
@@ -145,6 +150,7 @@
     private val qqsVisible = MutableStateFlow(false)
     private val qqsPositionOnRoot = Rect()
     private val composeViewPositionOnScreen = Rect()
+    private val scrollState = ScrollState(0)
 
     // Inside object for namespacing
     private val notificationScrimClippingParams =
@@ -210,6 +216,9 @@
                 context,
                 { notificationScrimClippingParams.isEnabled },
                 { notificationScrimClippingParams.params.top },
+                // Only allow scrolling when we are fully expanded. That way, we don't intercept
+                // swipes in lockscreen (when somehow QS is receiving touches).
+                { scrollState.canScrollForward && viewModel.expansionState.value.progress >= 1f },
             )
         frame.addView(
             composeView,
@@ -488,12 +497,8 @@
     private fun setListenerCollections() {
         lifecycleScope.launch {
             lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
-                launch {
-                    //                    TODO
-                    //                    setListenerJob(
-                    //                            scrollListener,
-                    //
-                    //                    )
+                this@QSFragmentCompose.view?.setSnapshotBinding {
+                    scrollListener.value?.onQsPanelScrollChanged(scrollState.value)
                 }
                 launch {
                     setListenerJob(
@@ -528,6 +533,7 @@
             viewModel.containerViewModel.quickQuickSettingsViewModel.squishinessViewModel
                 .squishiness
                 .collectAsStateWithLifecycle()
+
         Column(modifier = Modifier.sysuiResTag("quick_qs_panel")) {
             Box(
                 modifier =
@@ -591,7 +597,12 @@
                     modifier =
                         Modifier.element(ElementKeys.QuickSettingsContent).fillMaxSize().weight(1f)
                 ) {
-                    Column {
+                    DisposableEffect(Unit) {
+                        lifecycleScope.launch { scrollState.scrollTo(0) }
+                        onDispose { lifecycleScope.launch { scrollState.scrollTo(0) } }
+                    }
+
+                    Column(modifier = Modifier.verticalScroll(scrollState)) {
                         Spacer(
                             modifier = Modifier.height { qqsPadding + qsExtraPadding.roundToPx() }
                         )
@@ -601,15 +612,14 @@
                         )
                     }
                 }
-                QuickSettingsTheme {
-                    FooterActions(
-                        viewModel = viewModel.footerActionsViewModel,
-                        qsVisibilityLifecycleOwner = this@QSFragmentCompose,
-                        modifier =
-                            Modifier.sysuiResTag("qs_footer_actions")
-                                .element(ElementKeys.FooterActions),
-                    )
-                }
+            }
+            QuickSettingsTheme {
+                FooterActions(
+                    viewModel = viewModel.footerActionsViewModel,
+                    qsVisibilityLifecycleOwner = this@QSFragmentCompose,
+                    modifier =
+                        Modifier.sysuiResTag("qs_footer_actions").element(ElementKeys.FooterActions),
+                )
             }
         }
     }
@@ -791,13 +801,17 @@
 private const val EDIT_MODE_TIME_MILLIS = 500
 
 /**
- * Ignore touches below the value returned by [clippingTopProvider], when clipping is enabled, as
- * per [clippingEnabledProvider].
+ * Performs different touch handling based on the state of the ComposeView:
+ * * Ignore touches below the value returned by [clippingTopProvider], when clipping is enabled, as
+ *   per [clippingEnabledProvider].
+ * * Intercept touches that would overscroll QS forward and instead allow them to be used to close
+ *   the shade.
  */
 private class FrameLayoutTouchPassthrough(
     context: Context,
     private val clippingEnabledProvider: () -> Boolean,
     private val clippingTopProvider: () -> Int,
+    private val canScrollForwardQs: () -> Boolean,
 ) : FrameLayout(context) {
     override fun isTransformedTouchPointInView(
         x: Float,
@@ -811,4 +825,32 @@
             super.isTransformedTouchPointInView(x, y, child, outLocalPoint)
         }
     }
+
+    val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
+    var downY = 0f
+
+    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+        // If there's a touch on this view and we can scroll down, we don't want to be intercepted
+        val action = ev.actionMasked
+
+        when (action) {
+            MotionEvent.ACTION_DOWN -> {
+                // If we can scroll down, make sure none of our parents intercepts us.
+                if (canScrollForwardQs()) {
+                    parent?.requestDisallowInterceptTouchEvent(true)
+                }
+                downY = ev.y
+            }
+
+            MotionEvent.ACTION_MOVE -> {
+                val y = ev.y.toInt()
+                val yDiff: Float = y - downY
+                if (yDiff < -touchSlop && !canScrollForwardQs()) {
+                    // Intercept touches that are overscrolling.
+                    return true
+                }
+            }
+        }
+        return super.onInterceptTouchEvent(ev)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepository.kt
index 26b2e2b..424be90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepository.kt
@@ -38,6 +38,6 @@
 ) {
     val rows =
         configurationRepository.onConfigurationChange.emitOnStart().map {
-            resources.getInteger(R.integer.quick_settings_max_rows)
+            resources.getInteger(R.integer.quick_settings_paginated_grid_num_rows)
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
index f7c71ce..ee0cfb3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
@@ -34,6 +34,6 @@
 ) {
     val rows =
         configurationRepository.onConfigurationChange.emitOnStart().map {
-            resources.getInteger(R.integer.quick_qs_panel_max_rows)
+            resources.getInteger(R.integer.quick_qs_paginated_grid_num_rows)
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
new file mode 100644
index 0000000..b9994d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.compose
+
+import com.android.compose.animation.Bounceable
+import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.ui.model.GridCell
+import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+
+data class BounceableInfo(
+    val bounceable: BounceableTileViewModel,
+    val previousTile: Bounceable?,
+    val nextTile: Bounceable?,
+    val bounceEnd: Boolean,
+)
+
+fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo(
+    index: Int,
+    columns: Int,
+): BounceableInfo {
+    val cell = this[index].first as TileGridCell
+    // Only look for neighbor bounceables if they are on the same row
+    val onLastColumn = cell.onLastColumn(cell.column, columns)
+    val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 }
+    val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn }
+    return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn)
+}
+
+fun List<BounceableTileViewModel>.bounceableInfo(
+    sizedTile: SizedTile<TileViewModel>,
+    index: Int,
+    column: Int,
+    columns: Int,
+): BounceableInfo {
+    // Only look for neighbor bounceables if they are on the same row
+    val onLastColumn = sizedTile.onLastColumn(column, columns)
+    val previousTile = getOrNull(index - 1)?.takeIf { column != 0 }
+    val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn }
+    return BounceableInfo(this[index], previousTile, nextTile, !onLastColumn)
+}
+
+private fun <T> SizedTile<T>.onLastColumn(column: Int, columns: Int): Boolean {
+    return column == columns - width
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
index 770fd78..74fa0fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
@@ -116,9 +116,9 @@
             regenerateGrid()
             _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell)
         } else {
-            // Add the tile with a temporary row which will get reassigned when
+            // Add the tile with a temporary row/col which will get reassigned when
             // regenerating spacers
-            _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0))
+            _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0, 0))
         }
 
         regenerateGrid()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index e749475..d55763a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -19,7 +19,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.pager.HorizontalPager
 import androidx.compose.foundation.pager.rememberPagerState
 import androidx.compose.material.icons.Icons
@@ -97,7 +97,9 @@
                     TileGrid(tiles = page, modifier = Modifier, editModeStart = {})
                 }
             }
-            Box(modifier = Modifier.height(FooterHeight).fillMaxWidth()) {
+            // Use requiredHeight so it won't be squished if the view doesn't quite fit. As this is
+            // expected to be inside a scrollable container, this should not be an issue.
+            Box(modifier = Modifier.requiredHeight(FooterHeight).fillMaxWidth()) {
                 PagerDots(
                     pagerState = pagerState,
                     activeColor = MaterialTheme.colorScheme.primary,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index a645b51..1c7a334 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -20,6 +20,8 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.util.fastMap
@@ -29,6 +31,7 @@
 import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
 import com.android.systemui.qs.composefragment.ui.GridAnchor
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
 import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey
 import com.android.systemui.res.R
@@ -38,10 +41,11 @@
     viewModel: QuickQuickSettingsViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val sizedTiles by
-        viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList())
+    val sizedTiles by viewModel.tileViewModels.collectAsStateWithLifecycle()
     val tiles = sizedTiles.fastMap { it.tile }
+    val bounceables = remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } }
     val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle()
+    val scope = rememberCoroutineScope()
 
     DisposableEffect(tiles) {
         val token = Any()
@@ -49,6 +53,7 @@
         onDispose { tiles.forEach { it.stopListening(token) } }
     }
     val columns by viewModel.columns.collectAsStateWithLifecycle()
+    var cellIndex = 0
     Box(modifier = modifier) {
         GridAnchor()
         VerticalSpannedGrid(
@@ -59,11 +64,15 @@
             modifier = Modifier.sysuiResTag("qqs_tile_layout"),
         ) { spanIndex ->
             val it = sizedTiles[spanIndex]
+            val column = cellIndex % columns
+            cellIndex += it.width
             Tile(
                 tile = it.tile,
                 iconOnly = it.isIcon,
                 modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
                 squishiness = { squishiness },
+                coroutineScope = scope,
+                bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index 9ec5a82..71fa0ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -31,6 +31,7 @@
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -54,6 +55,7 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import com.android.compose.modifiers.background
 import com.android.compose.modifiers.thenIf
@@ -64,7 +66,6 @@
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
 import com.android.systemui.res.R
-import kotlinx.coroutines.delay
 
 private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target"
 
@@ -138,13 +139,20 @@
     accessibilityUiState: AccessibilityUiState? = null,
 ) {
     Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) {
-        Text(label, color = colors.label, modifier = Modifier.tileMarquee())
+        Text(
+            label,
+            style = MaterialTheme.typography.labelLarge,
+            color = colors.label,
+            maxLines = 1,
+            overflow = TextOverflow.Ellipsis,
+        )
         if (!TextUtils.isEmpty(secondaryLabel)) {
             Text(
                 secondaryLabel ?: "",
                 color = colors.secondaryLabel,
+                style = MaterialTheme.typography.bodyMedium,
                 modifier =
-                    Modifier.tileMarquee().thenIf(
+                    Modifier.thenIf(
                         accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") ==
                             true
                     ) {
@@ -182,10 +190,7 @@
                     rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true)
                 } else {
                     var atEnd by remember(icon.res) { mutableStateOf(false) }
-                    LaunchedEffect(key1 = icon.res) {
-                        delay(350)
-                        atEnd = true
-                    }
+                    LaunchedEffect(key1 = icon.res) { atEnd = true }
                     rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd)
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index 45c1e48..5c2a2bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -22,13 +22,13 @@
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.animateIntAsState
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.LocalOverscrollConfiguration
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
@@ -46,7 +46,6 @@
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyGridItemScope
 import androidx.compose.foundation.lazy.grid.LazyGridScope
 import androidx.compose.foundation.lazy.grid.rememberLazyGridState
 import androidx.compose.foundation.rememberScrollState
@@ -66,19 +65,17 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.BiasAlignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawBehind
-import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.geometry.CornerRadius
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.drawscope.Stroke
-import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.layout.positionInRoot
@@ -98,23 +95,26 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.compose.ui.util.fastMap
-import androidx.compose.ui.zIndex
+import com.android.compose.animation.bounceable
 import com.android.compose.modifiers.background
 import com.android.compose.modifiers.height
 import com.android.systemui.common.ui.compose.load
 import com.android.systemui.qs.panels.shared.model.SizedTile
 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.DragAndDropState
 import com.android.systemui.qs.panels.ui.compose.EditTileListState
+import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.dragAndDropRemoveZone
 import com.android.systemui.qs.panels.ui.compose.dragAndDropTileList
 import com.android.systemui.qs.panels.ui.compose.dragAndDropTileSource
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileArrangementPadding
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.ToggleTargetSize
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
 import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
-import com.android.systemui.qs.panels.ui.compose.selection.ResizingHandle
+import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer
 import com.android.systemui.qs.panels.ui.compose.selection.TileWidths
 import com.android.systemui.qs.panels.ui.compose.selection.clearSelectionTile
 import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
@@ -122,11 +122,14 @@
 import com.android.systemui.qs.panels.ui.model.GridCell
 import com.android.systemui.qs.panels.ui.model.SpacerGridCell
 import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.shared.model.groupAndSort
 import com.android.systemui.res.R
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 
 object TileType
 
@@ -241,15 +244,20 @@
     onSetTiles: (List<TileSpec>) -> Unit,
 ) {
     val currentListState by rememberUpdatedState(listState)
-    val tileHeight = CommonTileDefaults.TileHeight
     val totalRows = listState.tiles.lastOrNull()?.row ?: 0
     val totalHeight by
         animateDpAsState(
-            gridHeight(totalRows + 1, tileHeight, TileArrangementPadding, CurrentTilesGridPadding),
+            gridHeight(totalRows + 1, TileHeight, TileArrangementPadding, CurrentTilesGridPadding),
             label = "QSEditCurrentTilesGridHeight",
         )
     val gridState = rememberLazyGridState()
     var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
+    val coroutineScope = rememberCoroutineScope()
+
+    val cells =
+        remember(listState.tiles) {
+            listState.tiles.fastMap { Pair(it, BounceableTileViewModel()) }
+        }
 
     TileLazyGrid(
         state = gridState,
@@ -272,7 +280,7 @@
                 }
                 .testTag(CURRENT_TILES_GRID_TEST_TAG),
     ) {
-        EditTiles(listState.tiles, listState, selectionState) { spec ->
+        EditTiles(cells, columns, listState, selectionState, coroutineScope) { spec ->
             // Toggle the current size of the tile
             currentListState.isIcon(spec)?.let { onResize(spec, !it) }
         }
@@ -286,10 +294,10 @@
     columns: Int,
     dragAndDropState: DragAndDropState,
 ) {
-    // Available tiles aren't visible during drag and drop, so the row isn't needed
+    // Available tiles aren't visible during drag and drop, so the row/col isn't needed
     val groupedTiles =
         remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) {
-            groupAndSort(tiles.fastMap { TileGridCell(it, 0) })
+            groupAndSort(tiles.fastMap { TileGridCell(it, 0, 0) })
         }
     val labelColors = EditModeTileDefaults.editTileColors()
 
@@ -349,24 +357,26 @@
 /**
  * Adds a list of [GridCell] to the lazy grid
  *
- * @param cells the list of [GridCell]
+ * @param cells the pairs of [GridCell] to [BounceableTileViewModel]
  * @param dragAndDropState the [DragAndDropState] for this grid
  * @param selectionState the [MutableSelectionState] for this grid
  * @param onToggleSize the callback when a tile's size is toggled
  */
 fun LazyGridScope.EditTiles(
-    cells: List<GridCell>,
+    cells: List<Pair<GridCell, BounceableTileViewModel>>,
+    columns: Int,
     dragAndDropState: DragAndDropState,
     selectionState: MutableSelectionState,
+    coroutineScope: CoroutineScope,
     onToggleSize: (spec: TileSpec) -> Unit,
 ) {
     items(
         count = cells.size,
-        key = { cells[it].key(it, dragAndDropState) },
-        span = { cells[it].span },
+        key = { cells[it].first.key(it, dragAndDropState) },
+        span = { cells[it].first.span },
         contentType = { TileType },
     ) { index ->
-        when (val cell = cells[index]) {
+        when (val cell = cells[index].first) {
             is TileGridCell ->
                 if (dragAndDropState.isMoving(cell.tile.tileSpec)) {
                     // If the tile is being moved, replace it with a visible spacer
@@ -385,6 +395,9 @@
                         dragAndDropState = dragAndDropState,
                         selectionState = selectionState,
                         onToggleSize = onToggleSize,
+                        coroutineScope = coroutineScope,
+                        bounceableInfo = cells.bounceableInfo(index, columns),
+                        modifier = Modifier.animateItem(),
                     )
                 }
             is SpacerGridCell -> SpacerGridCell()
@@ -393,12 +406,15 @@
 }
 
 @Composable
-private fun LazyGridItemScope.TileGridCell(
+private fun TileGridCell(
     cell: TileGridCell,
     index: Int,
     dragAndDropState: DragAndDropState,
     selectionState: MutableSelectionState,
     onToggleSize: (spec: TileSpec) -> Unit,
+    coroutineScope: CoroutineScope,
+    bounceableInfo: BounceableInfo,
+    modifier: Modifier = Modifier,
 ) {
     val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
     var selected by remember { mutableStateOf(false) }
@@ -407,6 +423,9 @@
             targetValue = if (selected) 1f else 0f,
             label = "QSEditTileSelectionAlpha",
         )
+    val selectionColor = MaterialTheme.colorScheme.primary
+    val colors = EditModeTileDefaults.editTileColors()
+    val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
 
     LaunchedEffect(selectionState.selection?.tileSpec) {
         selectionState.selection?.let {
@@ -420,152 +439,61 @@
         selected = selectionState.selection?.tileSpec == cell.tile.tileSpec
     }
 
-    val modifier =
-        Modifier.animateItem()
-            .semantics(mergeDescendants = true) {
-                this.stateDescription = stateDescription
-                contentDescription = cell.tile.label.text
-                customActions =
-                    listOf(
-                        // TODO(b/367748260): Add final accessibility actions
-                        CustomAccessibilityAction("Toggle size") {
-                            onToggleSize(cell.tile.tileSpec)
-                            true
-                        }
-                    )
-            }
-            .height(CommonTileDefaults.TileHeight)
-            .fillMaxWidth()
-
-    val content =
-        @Composable {
-            EditTile(
-                tileViewModel = cell.tile,
-                iconOnly = cell.isIcon,
-                selectionAlpha = { selectionAlpha },
-                modifier =
-                    Modifier.fillMaxSize()
-                        .selectableTile(cell.tile.tileSpec, selectionState)
-                        .dragAndDropTileSource(
-                            SizedTileImpl(cell.tile, cell.width),
-                            dragAndDropState,
-                            selectionState::unSelect,
-                        ),
-            )
-        }
-
-    if (selected) {
-        SelectedTile(
-            isIcon = cell.isIcon,
-            selectionAlpha = { selectionAlpha },
-            selectionState = selectionState,
-            modifier = modifier.zIndex(2f), // 2f to display this tile over neighbors when dragged
-            content = content,
-        )
-    } else {
-        UnselectedTile(
-            selectionAlpha = { selectionAlpha },
-            selectionState = selectionState,
-            modifier = modifier,
-            content = content,
-        )
-    }
-}
-
-@Composable
-private fun SelectedTile(
-    isIcon: Boolean,
-    selectionAlpha: () -> Float,
-    selectionState: MutableSelectionState,
-    modifier: Modifier = Modifier,
-    content: @Composable () -> Unit,
-) {
     // Current base, min and max width of this tile
     var tileWidths: TileWidths? by remember { mutableStateOf(null) }
-
-    // Animated diff between the current width and the resized width of the tile. We can't use
-    // animateContentSize here as the tile is sometimes unbounded.
-    val remainingOffset by
-        animateIntAsState(
-            selectionState.resizingState?.let { tileWidths?.base?.minus(it.width) ?: 0 } ?: 0,
-            label = "QSEditTileWidthOffset",
-        )
-
     val padding = with(LocalDensity.current) { TileArrangementPadding.roundToPx() }
-    Box(
-        modifier.onSizeChanged {
-            val min = if (isIcon) it.width else (it.width - padding) / 2
-            val max = if (isIcon) (it.width * 2) + padding else it.width
-            tileWidths = TileWidths(it.width, min, max)
-        }
+
+    ResizableTileContainer(
+        selected = selected,
+        selectionState = selectionState,
+        selectionAlpha = { selectionAlpha },
+        selectionColor = selectionColor,
+        tileWidths = { tileWidths },
+        modifier =
+            modifier
+                .height(TileHeight)
+                .fillMaxWidth()
+                .onSizeChanged {
+                    // Grab the size before the bounceable to get the idle width
+                    val min = if (cell.isIcon) it.width else (it.width - padding) / 2
+                    val max = if (cell.isIcon) (it.width * 2) + padding else it.width
+                    tileWidths = TileWidths(it.width, min, max)
+                }
+                .bounceable(
+                    bounceable = currentBounceableInfo.bounceable,
+                    previousBounceable = currentBounceableInfo.previousTile,
+                    nextBounceable = currentBounceableInfo.nextTile,
+                    orientation = Orientation.Horizontal,
+                    bounceEnd = currentBounceableInfo.bounceEnd,
+                ),
     ) {
-        val handle =
-            @Composable {
-                ResizingHandle(
-                    enabled = true,
-                    selectionState = selectionState,
-                    transition = selectionAlpha,
-                    tileWidths = { tileWidths },
+        Box(
+            modifier
+                .fillMaxSize()
+                .semantics(mergeDescendants = true) {
+                    this.stateDescription = stateDescription
+                    contentDescription = cell.tile.label.text
+                    customActions =
+                        listOf(
+                            // TODO(b/367748260): Add final accessibility actions
+                            CustomAccessibilityAction("Toggle size") {
+                                onToggleSize(cell.tile.tileSpec)
+                                true
+                            }
+                        )
+                }
+                .selectableTile(cell.tile.tileSpec, selectionState) {
+                    coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+                }
+                .dragAndDropTileSource(
+                    SizedTileImpl(cell.tile, cell.width),
+                    dragAndDropState,
+                    selectionState::unSelect,
                 )
-            }
-
-        Layout(contents = listOf(content, handle)) {
-            (contentMeasurables, handleMeasurables),
-            constraints ->
-            // Grab the width from the resizing state if a resize is in progress, otherwise fill the
-            // max width
-            val width =
-                selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
-            val contentPlaceable =
-                contentMeasurables.first().measure(constraints.copy(maxWidth = width))
-            val handlePlaceable = handleMeasurables.first().measure(constraints)
-
-            // Place the dot vertically centered on the right edge
-            val handleX = contentPlaceable.width - (handlePlaceable.width / 2)
-            val handleY = (contentPlaceable.height / 2) - (handlePlaceable.height / 2)
-
-            layout(constraints.maxWidth, constraints.maxHeight) {
-                contentPlaceable.place(0, 0)
-                handlePlaceable.place(handleX, handleY)
-            }
-        }
-    }
-}
-
-@Composable
-private fun UnselectedTile(
-    selectionAlpha: () -> Float,
-    selectionState: MutableSelectionState,
-    modifier: Modifier = Modifier,
-    content: @Composable () -> Unit,
-) {
-    val handle =
-        @Composable {
-            ResizingHandle(
-                enabled = false,
-                selectionState = selectionState,
-                transition = selectionAlpha,
-            )
-        }
-
-    Box(modifier) {
-        Layout(contents = listOf(content, handle)) {
-            (contentMeasurables, handleMeasurables),
-            constraints ->
-            val contentPlaceable =
-                contentMeasurables
-                    .first()
-                    .measure(constraints.copy(maxWidth = constraints.maxWidth))
-            val handlePlaceable = handleMeasurables.first().measure(constraints)
-
-            // Place the dot vertically centered on the right edge
-            val handleX = contentPlaceable.width - (handlePlaceable.width / 2)
-            val handleY = (contentPlaceable.height / 2) - (handlePlaceable.height / 2)
-
-            layout(constraints.maxWidth, constraints.maxHeight) {
-                contentPlaceable.place(0, 0)
-                handlePlaceable.place(handleX, handleY)
-            }
+                .tileBackground(colors.background)
+                .tilePadding()
+        ) {
+            EditTile(tile = cell.tile, iconOnly = cell.isIcon)
         }
     }
 }
@@ -588,19 +516,19 @@
         verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
         modifier = modifier,
     ) {
-        EditTileContainer(
-            colors = colors,
-            modifier =
-                Modifier.fillMaxWidth()
-                    .height(CommonTileDefaults.TileHeight)
-                    .clearSelectionTile(selectionState)
-                    .semantics(mergeDescendants = true) {
-                        onClick(onClickActionName) { false }
-                        this.stateDescription = stateDescription
-                    }
-                    .dragAndDropTileSource(SizedTileImpl(cell.tile, cell.width), dragAndDropState) {
-                        selectionState.unSelect()
-                    },
+        Box(
+            Modifier.fillMaxWidth()
+                .height(TileHeight)
+                .clearSelectionTile(selectionState)
+                .semantics(mergeDescendants = true) {
+                    onClick(onClickActionName) { false }
+                    this.stateDescription = stateDescription
+                }
+                .dragAndDropTileSource(SizedTileImpl(cell.tile, cell.width), dragAndDropState) {
+                    selectionState.unSelect()
+                }
+                .tileBackground(colors.background)
+                .tilePadding()
         ) {
             // Icon
             SmallTileContent(
@@ -626,16 +554,14 @@
 @Composable
 private fun SpacerGridCell(modifier: Modifier = Modifier) {
     // By default, spacers are invisible and exist purely to catch drag movements
-    Box(modifier.height(CommonTileDefaults.TileHeight).fillMaxWidth())
+    Box(modifier.height(TileHeight).fillMaxWidth())
 }
 
 @Composable
-fun EditTile(
-    tileViewModel: EditTileViewModel,
+fun BoxScope.EditTile(
+    tile: EditTileViewModel,
     iconOnly: Boolean,
-    modifier: Modifier = Modifier,
     colors: TileColors = EditModeTileDefaults.editTileColors(),
-    selectionAlpha: () -> Float = { 1f },
 ) {
     // Animated horizontal alignment from center (0f) to start (-1f)
     val alignmentValue by
@@ -646,68 +572,36 @@
     val alignment by remember {
         derivedStateOf { BiasAlignment(horizontalBias = alignmentValue, verticalBias = 0f) }
     }
+    // Icon
+    Box(Modifier.size(ToggleTargetSize).align(alignment)) {
+        SmallTileContent(
+            icon = tile.icon,
+            color = colors.icon,
+            animateToEnd = true,
+            modifier = Modifier.align(Alignment.Center),
+        )
+    }
 
-    EditTileContainer(colors = colors, selectionAlpha = selectionAlpha, modifier = modifier) {
-        // Icon
-        Box(Modifier.size(ToggleTargetSize).align(alignment)) {
-            SmallTileContent(
-                icon = tileViewModel.icon,
-                color = colors.icon,
-                animateToEnd = true,
-                modifier = Modifier.align(Alignment.Center),
-            )
-        }
-
-        // Labels, positioned after the icon
-        AnimatedVisibility(visible = !iconOnly, enter = fadeIn(), exit = fadeOut()) {
-            LargeTileLabels(
-                label = tileViewModel.label.text,
-                secondaryLabel = tileViewModel.appName?.text,
-                colors = colors,
-                modifier = Modifier.padding(start = ToggleTargetSize + TileArrangementPadding),
-            )
-        }
+    // Labels, positioned after the icon
+    AnimatedVisibility(visible = !iconOnly, enter = fadeIn(), exit = fadeOut()) {
+        LargeTileLabels(
+            label = tile.label.text,
+            secondaryLabel = tile.appName?.text,
+            colors = colors,
+            modifier = Modifier.padding(start = ToggleTargetSize + TileArrangementPadding),
+        )
     }
 }
 
-@Composable
-private fun EditTileContainer(
-    colors: TileColors,
-    modifier: Modifier = Modifier,
-    selectionAlpha: () -> Float = { 0f },
-    selectionColor: Color = MaterialTheme.colorScheme.primary,
-    content: @Composable BoxScope.() -> Unit = {},
-) {
-    Box(
-        Modifier.wrapContentSize().drawWithContent {
-            drawContent()
-            drawRoundRect(
-                SolidColor(selectionColor),
-                cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
-                style = Stroke(EditModeTileDefaults.SelectedBorderWidth.toPx()),
-                alpha = selectionAlpha(),
-            )
-        }
-    ) {
-        Box(
-            modifier =
-                modifier
-                    .drawBehind {
-                        drawRoundRect(
-                            SolidColor(colors.background),
-                            cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
-                        )
-                    }
-                    .tilePadding(),
-            content = content,
-        )
+private fun Modifier.tileBackground(color: Color): Modifier {
+    return drawBehind {
+        drawRoundRect(SolidColor(color), cornerRadius = CornerRadius(InactiveCornerRadius.toPx()))
     }
 }
 
 private object EditModeTileDefaults {
     const val PLACEHOLDER_ALPHA = .3f
     val EditGridHeaderHeight = 60.dp
-    val SelectedBorderWidth = 2.dp
     val CurrentTilesGridPadding = 8.dp
 
     @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 6920e49..e5c2135 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -20,6 +20,7 @@
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.util.fastMap
@@ -29,7 +30,9 @@
 import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
 import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
+import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.rememberEditListState
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.QSColumnsViewModel
@@ -62,7 +65,11 @@
         }
         val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle()
         val sizedTiles = tiles.map { SizedTileImpl(it, it.spec.width()) }
+        val bounceables =
+            remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } }
         val squishiness by squishinessViewModel.squishiness.collectAsStateWithLifecycle()
+        val scope = rememberCoroutineScope()
+        var cellIndex = 0
 
         VerticalSpannedGrid(
             columns = columns,
@@ -71,11 +78,15 @@
             spans = sizedTiles.fastMap { it.width },
         ) { spanIndex ->
             val it = sizedTiles[spanIndex]
+            val column = cellIndex % columns
+            cellIndex += it.width
             Tile(
                 tile = it.tile,
                 iconOnly = iconTilesViewModel.isIconTile(it.tile.spec),
                 modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
                 squishiness = { squishiness },
+                coroutineScope = scope,
+                bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index 4bd5b2d..52d5261 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -23,8 +23,8 @@
 import android.service.quicksettings.Tile.STATE_INACTIVE
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Box
@@ -44,6 +44,7 @@
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
@@ -61,11 +62,13 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Expandable
+import com.android.compose.animation.bounceable
 import com.android.compose.modifiers.thenIf
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
@@ -74,6 +77,8 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.res.R
 import java.util.function.Supplier
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 private const val TEST_TAG_SMALL = "qs_tile_small"
 private const val TEST_TAG_LARGE = "qs_tile_large"
@@ -102,9 +107,12 @@
     tile: TileViewModel,
     iconOnly: Boolean,
     squishiness: () -> Float,
+    coroutineScope: CoroutineScope,
+    bounceableInfo: BounceableInfo,
     modifier: Modifier = Modifier,
 ) {
     val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
+    val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
     val resources = resources()
     val uiState = remember(state, resources) { state.toUiState(resources) }
     val colors = TileDefaults.getColorForState(uiState)
@@ -112,7 +120,7 @@
     // TODO(b/361789146): Draw the shapes instead of clipping
     val tileShape = TileDefaults.animateTileShape(uiState.state)
 
-    TileContainer(
+    TileExpandable(
         color =
             if (iconOnly || !uiState.handlesSecondaryClick) {
                 colors.iconBackground
@@ -120,93 +128,101 @@
                 colors.background
             },
         shape = tileShape,
-        iconOnly = iconOnly,
-        onClick = tile::onClick,
-        onLongClick = tile::onLongClick,
-        uiState = uiState,
         squishiness = squishiness,
-        modifier = modifier,
+        modifier =
+            modifier
+                .fillMaxWidth()
+                .bounceable(
+                    bounceable = currentBounceableInfo.bounceable,
+                    previousBounceable = currentBounceableInfo.previousTile,
+                    nextBounceable = currentBounceableInfo.nextTile,
+                    orientation = Orientation.Horizontal,
+                    bounceEnd = currentBounceableInfo.bounceEnd,
+                ),
     ) { expandable ->
-        val icon = getTileIcon(icon = uiState.icon)
-        if (iconOnly) {
-            SmallTileContent(
-                icon = icon,
-                color = colors.icon,
-                modifier = Modifier.align(Alignment.Center),
-            )
-        } else {
-            val iconShape = TileDefaults.animateIconShape(uiState.state)
-            LargeTileContent(
-                label = uiState.label,
-                secondaryLabel = uiState.secondaryLabel,
-                icon = icon,
-                colors = colors,
-                iconShape = iconShape,
-                toggleClickSupported = state.handlesSecondaryClick,
-                onClick = {
-                    if (state.handlesSecondaryClick) {
-                        tile.onSecondaryClick()
-                    }
-                },
-                onLongClick = { tile.onLongClick(expandable) },
-                accessibilityUiState = uiState.accessibilityUiState,
-                squishiness = squishiness,
-            )
+        TileContainer(
+            onClick = {
+                tile.onClick(expandable)
+                if (uiState.accessibilityUiState.toggleableState != null) {
+                    coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+                }
+            },
+            onLongClick = { tile.onLongClick(expandable) },
+            uiState = uiState,
+            iconOnly = iconOnly,
+        ) {
+            val icon = getTileIcon(icon = uiState.icon)
+            if (iconOnly) {
+                SmallTileContent(
+                    icon = icon,
+                    color = colors.icon,
+                    modifier = Modifier.align(Alignment.Center),
+                )
+            } else {
+                val iconShape = TileDefaults.animateIconShape(uiState.state)
+                LargeTileContent(
+                    label = uiState.label,
+                    secondaryLabel = uiState.secondaryLabel,
+                    icon = icon,
+                    colors = colors,
+                    iconShape = iconShape,
+                    toggleClickSupported = state.handlesSecondaryClick,
+                    onClick = {
+                        if (state.handlesSecondaryClick) {
+                            tile.onSecondaryClick()
+                        }
+                    },
+                    onLongClick = { tile.onLongClick(expandable) },
+                    accessibilityUiState = uiState.accessibilityUiState,
+                    squishiness = squishiness,
+                )
+            }
         }
     }
 }
 
 @Composable
-private fun TileContainer(
+private fun TileExpandable(
     color: Color,
     shape: Shape,
-    iconOnly: Boolean,
-    uiState: TileUiState,
     squishiness: () -> Float,
     modifier: Modifier = Modifier,
-    onClick: (Expandable) -> Unit = {},
-    onLongClick: (Expandable) -> Unit = {},
-    content: @Composable BoxScope.(Expandable) -> Unit,
+    content: @Composable (Expandable) -> Unit,
 ) {
     Expandable(
         color = color,
         shape = shape,
         modifier = modifier.clip(shape).verticalSquish(squishiness),
     ) {
-        val longPressLabel = longPressLabel()
-        Box(
-            modifier =
-                Modifier.height(CommonTileDefaults.TileHeight)
-                    .fillMaxWidth()
-                    .combinedClickable(
-                        onClick = { onClick(it) },
-                        onLongClick = { onLongClick(it) },
-                        onClickLabel = uiState.accessibilityUiState.clickLabel,
-                        onLongClickLabel = longPressLabel,
-                    )
-                    .semantics {
-                        role = uiState.accessibilityUiState.accessibilityRole
-                        if (uiState.accessibilityUiState.accessibilityRole == Role.Switch) {
-                            uiState.accessibilityUiState.toggleableState?.let {
-                                toggleableState = it
-                            }
-                        }
-                        stateDescription = uiState.accessibilityUiState.stateDescription
-                    }
-                    .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
-                    .thenIf(iconOnly) {
-                        Modifier.semantics {
-                            contentDescription = uiState.accessibilityUiState.contentDescription
-                        }
-                    }
-                    .tilePadding()
-        ) {
-            content(it)
-        }
+        content(it)
     }
 }
 
 @Composable
+fun TileContainer(
+    onClick: () -> Unit,
+    onLongClick: () -> Unit,
+    uiState: TileUiState,
+    iconOnly: Boolean,
+    content: @Composable BoxScope.() -> Unit,
+) {
+    Box(
+        modifier =
+            Modifier.height(CommonTileDefaults.TileHeight)
+                .fillMaxWidth()
+                .tileCombinedClickable(
+                    onClick = onClick,
+                    onLongClick = onLongClick,
+                    uiState = uiState,
+                    iconOnly = iconOnly,
+                )
+                .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
+                .tilePadding(),
+        content = content,
+    )
+}
+
+@Composable
 private fun getTileIcon(icon: Supplier<QSTile.Icon?>): Icon {
     val context = LocalContext.current
     return icon.get()?.let {
@@ -222,14 +238,38 @@
     return spacedBy(space = CommonTileDefaults.TileArrangementPadding, alignment = Alignment.Start)
 }
 
-fun Modifier.tileMarquee(): Modifier {
-    return basicMarquee(iterations = 1, initialDelayMillis = 200)
-}
-
 fun Modifier.tilePadding(): Modifier {
     return padding(CommonTileDefaults.TilePadding)
 }
 
+@Composable
+fun Modifier.tileCombinedClickable(
+    onClick: () -> Unit,
+    onLongClick: () -> Unit,
+    uiState: TileUiState,
+    iconOnly: Boolean,
+): Modifier {
+    val longPressLabel = longPressLabel()
+    return combinedClickable(
+            onClick = onClick,
+            onLongClick = onLongClick,
+            onClickLabel = uiState.accessibilityUiState.clickLabel,
+            onLongClickLabel = longPressLabel,
+        )
+        .semantics {
+            role = uiState.accessibilityUiState.accessibilityRole
+            if (uiState.accessibilityUiState.accessibilityRole == Role.Switch) {
+                uiState.accessibilityUiState.toggleableState?.let { toggleableState = it }
+            }
+            stateDescription = uiState.accessibilityUiState.stateDescription
+        }
+        .thenIf(iconOnly) {
+            Modifier.semantics {
+                contentDescription = uiState.accessibilityUiState.contentDescription
+            }
+        }
+}
+
 data class TileColors(
     val background: Color,
     val iconBackground: Color,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
index 441d962..1d36aee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
@@ -89,8 +89,11 @@
  * Listens for click events to select/unselect the given [TileSpec]. Use this on current tiles as
  * they can be selected.
  */
-@Composable
-fun Modifier.selectableTile(tileSpec: TileSpec, selectionState: MutableSelectionState): Modifier {
+fun Modifier.selectableTile(
+    tileSpec: TileSpec,
+    selectionState: MutableSelectionState,
+    onClick: () -> Unit = {},
+): Modifier {
     return pointerInput(Unit) {
         detectTapGestures(
             onTap = {
@@ -99,6 +102,7 @@
                 } else {
                     selectionState.select(tileSpec, manual = true)
                 }
+                onClick()
             }
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index e0f0b6a..9f13a37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -16,63 +16,117 @@
 
 package com.android.systemui.qs.panels.ui.compose.selection
 
+import androidx.compose.animation.core.animateIntAsState
 import androidx.compose.foundation.Canvas
 import androidx.compose.foundation.gestures.detectHorizontalDragGestures
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.systemGestureExclusion
 import androidx.compose.material3.LocalMinimumInteractiveComponentSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.geometry.CornerRadius
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.toSize
+import androidx.compose.ui.zIndex
+import com.android.compose.modifiers.thenIf
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth
 
 /**
- * Dot handling resizing drag events. Use this on the selected tile to resize it
+ * Places a dot to handle resizing drag events. Use this on tiles to resize.
  *
- * @param enabled whether resizing drag events should be handled
+ * The dot is placed vertically centered on the right border. The [content] will have a border when
+ * selected.
+ *
+ * @param selected whether resizing drag events should be handled
  * @param selectionState the [MutableSelectionState] on the grid
- * @param transition the animated value for the dot, used for its alpha and scale
+ * @param selectionAlpha the animated value for the dot and border alpha
+ * @param selectionColor the [Color] of the dot and border
  * @param tileWidths the [TileWidths] of the selected tile
- * @param onResize the callback when the drag passes the resizing threshold
  */
 @Composable
-fun ResizingHandle(
+fun ResizableTileContainer(
+    selected: Boolean,
+    selectionState: MutableSelectionState,
+    selectionAlpha: () -> Float,
+    selectionColor: Color,
+    tileWidths: () -> TileWidths?,
+    modifier: Modifier = Modifier,
+    content: @Composable BoxScope.() -> Unit = {},
+) {
+    Box(
+        modifier
+            .resizable(selected, selectionState, tileWidths)
+            .selectionBorder(selectionColor, selectionAlpha)
+    ) {
+        content()
+        ResizingHandle(
+            enabled = selected,
+            selectionState = selectionState,
+            transition = selectionAlpha,
+            tileWidths = tileWidths,
+            modifier =
+                // Higher zIndex to make sure the handle is drawn above the content
+                Modifier.zIndex(2f),
+        )
+    }
+}
+
+@Composable
+private fun ResizingHandle(
     enabled: Boolean,
     selectionState: MutableSelectionState,
     transition: () -> Float,
-    tileWidths: () -> TileWidths? = { null },
+    tileWidths: () -> TileWidths?,
+    modifier: Modifier = Modifier,
 ) {
-    if (enabled) {
-        // Manually creating the touch target around the resizing dot to ensure that the next tile
-        // does
-        // not receive the touch input accidentally.
-        val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
-        Box(
-            Modifier.size(minTouchTargetSize)
-                .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
-                .pointerInput(Unit) {
-                    detectHorizontalDragGestures(
-                        onHorizontalDrag = { _, offset -> selectionState.onResizingDrag(offset) },
-                        onDragStart = {
-                            tileWidths()?.let { selectionState.onResizingDragStart(it) }
-                        },
-                        onDragEnd = selectionState::onResizingDragEnd,
-                        onDragCancel = selectionState::onResizingDragEnd,
+    // Manually creating the touch target around the resizing dot to ensure that the next tile
+    // does not receive the touch input accidentally.
+    val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
+    Box(
+        modifier
+            .layout { measurable, constraints ->
+                val size = minTouchTargetSize.roundToPx()
+                val placeable = measurable.measure(Constraints(size, size, size, size))
+                layout(placeable.width, placeable.height) {
+                    placeable.place(
+                        x = constraints.maxWidth - placeable.width / 2,
+                        y = constraints.maxHeight / 2 - placeable.height / 2,
                     )
                 }
-        ) {
-            ResizingDot(transition = transition, modifier = Modifier.align(Alignment.Center))
-        }
-    } else {
-        ResizingDot(transition = transition)
+            }
+            .thenIf(enabled) {
+                Modifier.systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
+                    .pointerInput(Unit) {
+                        detectHorizontalDragGestures(
+                            onHorizontalDrag = { _, offset ->
+                                selectionState.onResizingDrag(offset)
+                            },
+                            onDragStart = {
+                                tileWidths()?.let { selectionState.onResizingDragStart(it) }
+                            },
+                            onDragEnd = selectionState::onResizingDragEnd,
+                            onDragCancel = selectionState::onResizingDragEnd,
+                        )
+                    }
+            }
+    ) {
+        ResizingDot(transition = transition, modifier = Modifier.align(Alignment.Center))
     }
 }
 
@@ -88,6 +142,45 @@
     }
 }
 
+private fun Modifier.selectionBorder(
+    selectionColor: Color,
+    selectionAlpha: () -> Float = { 0f },
+): Modifier {
+    return drawWithContent {
+        drawContent()
+        drawRoundRect(
+            SolidColor(selectionColor),
+            cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
+            style = Stroke(SelectedBorderWidth.toPx()),
+            alpha = selectionAlpha(),
+        )
+    }
+}
+
+@Composable
+private fun Modifier.resizable(
+    selected: Boolean,
+    selectionState: MutableSelectionState,
+    tileWidths: () -> TileWidths?,
+): Modifier {
+    if (!selected) return zIndex(1f)
+
+    // Animated diff between the current width and the resized width of the tile. We can't use
+    // animateContentSize here as the tile is sometimes unbounded.
+    val remainingOffset by
+        animateIntAsState(
+            selectionState.resizingState?.let { tileWidths()?.base?.minus(it.width) ?: 0 } ?: 0,
+            label = "QSEditTileWidthOffset",
+        )
+    return zIndex(2f).layout { measurable, constraints ->
+        // Grab the width from the resizing state if a resize is in progress
+        val width = selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
+        val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width))
+        layout(constraints.maxWidth, placeable.height) { placeable.place(0, 0) }
+    }
+}
+
 private object SelectionDefaults {
     val ResizingDotSize = 16.dp
+    val SelectedBorderWidth = 2.dp
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
index b1841c4..c0441f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
@@ -31,8 +31,8 @@
 }
 
 /**
- * Represents a [EditTileViewModel] from a grid associated with a tile format and the row it's
- * positioned at
+ * Represents a [EditTileViewModel] from a grid associated with a tile format and the row and column
+ * it's positioned at
  */
 @Immutable
 data class TileGridCell(
@@ -41,13 +41,15 @@
     override val width: Int,
     override val span: GridItemSpan = GridItemSpan(width),
     override val s: String = "${tile.tileSpec.spec}-$row-$width",
+    val column: Int,
 ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile {
     val key: String = "${tile.tileSpec.spec}-$row"
 
     constructor(
         sizedTile: SizedTile<EditTileViewModel>,
         row: Int,
-    ) : this(tile = sizedTile.tile, row = row, width = sizedTile.width)
+        column: Int,
+    ) : this(tile = sizedTile.tile, row = row, column = column, width = sizedTile.width)
 }
 
 /** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */
@@ -73,7 +75,13 @@
     return splitInRowsSequence(this, columns)
         .flatMapIndexed { rowIndex, sizedTiles ->
             val correctedRowIndex = rowIndex + startingRow
-            val row: List<GridCell> = sizedTiles.map { TileGridCell(it, correctedRowIndex) }
+            var column = 0
+            val row: List<GridCell> =
+                sizedTiles.map {
+                    TileGridCell(it, correctedRowIndex, column).also { cell ->
+                        column += cell.width
+                    }
+                }
 
             // Fill the incomplete rows with spacers
             val numSpacers = columns - sizedTiles.sumOf { it.width }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/BounceableTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/BounceableTileViewModel.kt
new file mode 100644
index 0000000..506b052
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/BounceableTileViewModel.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.viewmodel
+
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.Bounceable
+
+class BounceableTileViewModel : Bounceable {
+    private val animatableBounce = Animatable(0.dp, Dp.VectorConverter)
+    override val bounce: Dp
+        get() = animatableBounce.value
+
+    suspend fun animateBounce() {
+        animatableBounce.animateTo(BounceSize)
+        animatableBounce.animateTo(0.dp)
+    }
+
+    private companion object {
+        val BounceSize = 8.dp
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt
index ee12736f..be6ce5c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt
@@ -43,13 +43,13 @@
 ) {
     fun load(context: Context): EditTileViewModel {
         return EditTileViewModel(
-            tileSpec,
-            icon,
-            label.toAnnotatedString(context) ?: AnnotatedString(tileSpec.spec),
-            appName?.toAnnotatedString(context),
-            isCurrent,
-            availableEditActions,
-            category,
+            tileSpec = tileSpec,
+            icon = icon,
+            label = label.toAnnotatedString(context) ?: AnnotatedString(tileSpec.spec),
+            appName = appName?.toAnnotatedString(context),
+            isCurrent = isCurrent,
+            availableEditActions = availableEditActions,
+            category = category,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
index b8f4ab4..dde3628 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.qs.tiles.base.viewmodel
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -28,5 +28,7 @@
 constructor(@Application private val applicationScope: CoroutineScope) {
 
     fun create(): CoroutineScope =
-        CoroutineScope(applicationScope.coroutineContext + SupervisorJob() + createCoroutineTracingContext("QSTileScope"))
+        CoroutineScope(
+            applicationScope.coroutineContext + SupervisorJob() + newTracingContext("QSTileScope")
+        )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
index ae56c2a..f674971 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
@@ -15,12 +15,12 @@
  */
 package com.android.systemui.qs.tiles.dialog
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.util.Log
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.animation.Expandable
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -63,7 +63,7 @@
             }
             return
         } else {
-            coroutineScope = CoroutineScope(bgDispatcher + createCoroutineTracingContext("InternetDialogScope"))
+            coroutineScope = CoroutineScope(bgDispatcher + newTracingContext("InternetDialogScope"))
             dialog =
                 dialogFactory
                     .create(aboveStatusBar, canConfigMobileData, canConfigWifi, coroutineScope)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
index ac75932..1411544 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
@@ -16,9 +16,9 @@
 
 package com.android.systemui.qs.tiles.impl.location.domain.interactor
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.content.Intent
 import android.provider.Settings
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.plugins.ActivityStarter
@@ -53,9 +53,11 @@
                     val wasEnabled: Boolean = input.data.isEnabled
                     if (keyguardController.isMethodSecure() && keyguardController.isShowing()) {
                         activityStarter.postQSRunnableDismissingKeyguard {
-                            CoroutineScope(applicationScope.coroutineContext + createCoroutineTracingContext("LocationTileScope")).launch {
-                                locationController.setLocationEnabled(!wasEnabled)
-                            }
+                            CoroutineScope(
+                                    applicationScope.coroutineContext +
+                                        newTracingContext("LocationTileScope")
+                                )
+                                .launch { locationController.setLocationEnabled(!wasEnabled) }
                         }
                     } else {
                         withContext(coroutineContext) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 40591bf..cc14e71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.content.Context
 import android.os.UserHandle
-import com.android.app.tracing.coroutines.flow.map
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.dagger.qualifiers.Background
@@ -37,6 +37,7 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
 
 class ModesTileDataInteractor
 @Inject
@@ -59,6 +60,7 @@
     fun tileData() =
         zenModeInteractor.activeModes
             .map { activeModes -> buildTileData(activeModes) }
+            .flowName("tileData")
             .flowOn(bgDispatcher)
             .distinctUntilChanged()
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
index 468e180..f03c752 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
@@ -16,12 +16,12 @@
 
 package com.android.systemui.qs.tiles.impl.saver.domain
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.content.Context
 import android.content.DialogInterface
 import android.content.SharedPreferences
 import android.os.Bundle
 import com.android.internal.R
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.qs.tiles.impl.saver.domain.interactor.DataSaverTileUserActionInteractor
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.policy.DataSaverController
@@ -45,9 +45,8 @@
             setTitle(R.string.data_saver_enable_title)
             setMessage(R.string.data_saver_description)
             setPositiveButton(R.string.data_saver_enable_button) { _: DialogInterface?, _ ->
-                CoroutineScope(backgroundContext + createCoroutineTracingContext("DataSaverDialogScope")).launch {
-                    dataSaverController.setDataSaverEnabled(true)
-                }
+                CoroutineScope(backgroundContext + newTracingContext("DataSaverDialogScope"))
+                    .launch { dataSaverController.setDataSaverEnabled(true) }
 
                 sharedPreferences
                     .edit()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index ce942fe..47254775 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -19,7 +19,7 @@
 import android.view.MotionEvent
 import android.view.View
 import androidx.compose.runtime.getValue
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.DefaultEdgeDetector
 import com.android.compose.animation.scene.ObservableTransitionState
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 700253ba..c3de067 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -61,6 +61,9 @@
 
     private static final int USER_ID_NOT_SPECIFIED = -1;
     protected static final int NOTIF_BASE_ID = 4273;
+    protected static final int NOTIF_GROUP_ID_SAVED = NOTIF_BASE_ID + 1;
+    protected static final int NOTIF_GROUP_ID_ERROR_SAVING = NOTIF_BASE_ID + 2;
+    protected static final int NOTIF_GROUP_ID_ERROR_STARTING = NOTIF_BASE_ID + 3;
     private static final String TAG = "RecordingService";
     private static final String CHANNEL_ID = "screen_record";
     @VisibleForTesting static final String GROUP_KEY_SAVED = "screen_record_saved";
@@ -280,7 +283,11 @@
      */
     @VisibleForTesting
     protected void createErrorStartingNotification(UserHandle currentUser) {
-        createErrorNotification(currentUser, strings().getStartError(), GROUP_KEY_ERROR_STARTING);
+        createErrorNotification(
+                currentUser,
+                strings().getStartError(),
+                GROUP_KEY_ERROR_STARTING,
+                NOTIF_GROUP_ID_ERROR_STARTING);
     }
 
     /**
@@ -289,13 +296,21 @@
      */
     @VisibleForTesting
     protected void createErrorSavingNotification(UserHandle currentUser) {
-        createErrorNotification(currentUser, strings().getSaveError(), GROUP_KEY_ERROR_SAVING);
+        createErrorNotification(
+                currentUser,
+                strings().getSaveError(),
+                GROUP_KEY_ERROR_SAVING,
+                NOTIF_GROUP_ID_ERROR_SAVING);
     }
 
     private void createErrorNotification(
-            UserHandle currentUser, String notificationContentTitle, String groupKey) {
+            UserHandle currentUser,
+            String notificationContentTitle,
+            String groupKey,
+            int notificationIdForGroup) {
         // Make sure error notifications get their own group.
-        postGroupSummaryNotification(currentUser, notificationContentTitle, groupKey);
+        postGroupSummaryNotification(
+                currentUser, notificationContentTitle, groupKey, notificationIdForGroup);
 
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, strings().getTitle());
@@ -410,17 +425,20 @@
     }
 
     /**
-     * Adds a group summary notification for save notifications so that save notifications from
-     * multiple recordings are grouped together, and the foreground service recording notification
-     * is not.
+     * Posts a group summary notification for the given group.
+     *
+     * Notifications that should be grouped:
+     *  - Save notifications
+     *  - Error saving notifications
+     *  - Error starting notifications
+     *
+     * The foreground service recording notification should never be grouped.
      */
-    private void postGroupSummaryNotificationForSaves(UserHandle currentUser) {
-        postGroupSummaryNotification(currentUser, strings().getSaveTitle(), GROUP_KEY_SAVED);
-    }
-
-    /** Posts a group summary notification for the given group. */
     private void postGroupSummaryNotification(
-            UserHandle currentUser, String notificationContentTitle, String groupKey) {
+            UserHandle currentUser,
+            String notificationContentTitle,
+            String groupKey,
+            int notificationIdForGroup) {
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
                 strings().getTitle());
@@ -431,7 +449,8 @@
                 .setGroupSummary(true)
                 .setExtras(extras)
                 .build();
-        mNotificationManager.notifyAsUser(getTag(), mNotificationId, groupNotif, currentUser);
+        mNotificationManager.notifyAsUser(
+                getTag(), notificationIdForGroup, groupNotif, currentUser);
     }
 
     private void stopService() {
@@ -484,7 +503,11 @@
                 Log.d(getTag(), "saving recording");
                 Notification notification = createSaveNotification(
                         getRecorder() != null ? getRecorder().save() : null);
-                postGroupSummaryNotificationForSaves(currentUser);
+                postGroupSummaryNotification(
+                        currentUser,
+                        strings().getSaveTitle(),
+                        GROUP_KEY_SAVED,
+                        NOTIF_GROUP_ID_SAVED);
                 mNotificationManager.notifyAsUser(null, mNotificationId,  notification,
                         currentUser);
             } catch (IOException | IllegalStateException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
index 54e0319..17b1b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
@@ -26,7 +26,7 @@
 import android.util.Log
 import android.util.Pair
 import android.view.Window
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.app.ChooserActivity
 import com.android.systemui.dagger.qualifiers.Application
 import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 9e62280..7b01c36 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -31,7 +31,7 @@
 import android.view.RemoteAnimationTarget
 import android.view.WindowManager
 import android.view.WindowManagerGlobal
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.infra.ServiceConnector
 import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
index c8067df..6df22f0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -21,7 +21,7 @@
 import android.util.Log
 import androidx.lifecycle.LifecycleService
 import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.shade.ShadeExpansionStateManager
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
index d3a7fc4a..7aeec47 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
@@ -18,7 +18,7 @@
 
 import android.media.MediaPlayer
 import android.util.Log
-import com.android.app.tracing.coroutines.async
+import com.android.app.tracing.coroutines.asyncTraced as async
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 757e37e..d652d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -123,7 +123,6 @@
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.dump.DumpsysTableLogger;
@@ -1859,16 +1858,11 @@
     /** Returns space between top of lock icon and bottom of NotificationStackScrollLayout. */
     private float getLockIconPadding() {
         float lockIconPadding = 0f;
-        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-            View deviceEntryIconView = mKeyguardViewConfigurator.getKeyguardRootView()
-                    .findViewById(R.id.device_entry_icon_view);
-            if (deviceEntryIconView != null) {
-                lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
-                    - deviceEntryIconView.getTop();
-            }
-        } else if (mLockIconViewController.getTop() != 0f) {
+        View deviceEntryIconView = mKeyguardViewConfigurator.getKeyguardRootView()
+                .findViewById(R.id.device_entry_icon_view);
+        if (deviceEntryIconView != null) {
             lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
-                    - mLockIconViewController.getTop();
+                - deviceEntryIconView.getTop();
         }
         return lockIconPadding;
     }
@@ -5059,8 +5053,7 @@
                 return false;
             }
 
-            if (DeviceEntryUdfpsRefactor.isEnabled()
-                    && mAlternateBouncerInteractor.isVisibleState()) {
+            if (mAlternateBouncerInteractor.isVisibleState()) {
                 // never send touches to shade if the alternate bouncer is showing
                 return false;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index cae141d..5699557 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -35,7 +35,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.KeyguardUnfoldTransition;
-import com.android.keyguard.LockIconViewController;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityTransitionAnimator;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -44,7 +43,6 @@
 import com.android.systemui.bouncer.ui.binder.BouncerViewBinder;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlagsClassic;
@@ -75,7 +73,6 @@
 import com.android.systemui.statusbar.phone.DozeScrimController;
 import com.android.systemui.statusbar.phone.DozeServiceHost;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
@@ -101,9 +98,7 @@
     private final NotificationShadeDepthController mDepthController;
     private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    private final LockIconViewController mLockIconViewController;
     private final ShadeLogger mShadeLogger;
-    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final StatusBarWindowStateController mStatusBarWindowStateController;
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private final AmbientState mAmbientState;
@@ -174,9 +169,7 @@
             PanelExpansionInteractor panelExpansionInteractor,
             ShadeExpansionStateManager shadeExpansionStateManager,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             StatusBarWindowStateController statusBarWindowStateController,
-            LockIconViewController lockIconViewController,
             CentralSurfaces centralSurfaces,
             DozeServiceHost dozeServiceHost,
             DozeScrimController dozeScrimController,
@@ -210,9 +203,7 @@
         mShadeExpansionStateManager = shadeExpansionStateManager;
         mDepthController = depthController;
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
-        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mStatusBarWindowStateController = statusBarWindowStateController;
-        mLockIconViewController = lockIconViewController;
         mShadeLogger = shadeLogger;
         mService = centralSurfaces;
         mDozeServiceHost = dozeServiceHost;
@@ -259,7 +250,6 @@
                             mDisableSubpixelTextTransitionListener));
         }
 
-        lockIconViewController.setLockIconView(mView.findViewById(R.id.lock_icon_view));
         dumpManager.registerDumpable(this);
     }
 
@@ -392,9 +382,6 @@
                 }
 
                 if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
-                    // If the user was sliding their finger across the lock screen,
-                    // we may have been intercepting the touch and forwarding it to the
-                    // UDFPS affordance via mStatusBarKeyguardViewManager.onTouch (see below).
                     // If this touch ended up unlocking the device, we want to cancel the touch
                     // immediately, so we don't cause swipe or expand animations afterwards.
                     cancelCurrentTouch();
@@ -419,9 +406,6 @@
                         && mDreamingWakeupGestureHandler.onTouchEvent(ev)) {
                     return logDownDispatch(ev, "dream wakeup gesture handled", true);
                 }
-                if (mStatusBarKeyguardViewManager.dispatchTouchEvent(ev)) {
-                    return logDownDispatch(ev, "dispatched to Keyguard", true);
-                }
                 if (mBrightnessMirror != null
                         && mBrightnessMirror.getVisibility() == View.VISIBLE) {
                     // Disallow new pointers while the brightness mirror is visible. This is so that
@@ -512,7 +496,6 @@
                 if (mStatusBarStateController.isDozing()
                         && !mDozeServiceHost.isPulsing()
                         && !mDockManager.isDocked()
-                        && !mLockIconViewController.willHandleTouchWhileDozing(ev)
                 ) {
                     if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                         mShadeLogger.d("NSWVC: capture all touch events in always-on");
@@ -520,22 +503,8 @@
                     return true;
                 }
 
-                if (mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(ev)) {
-                    // Don't allow touches to proceed to underlying views if alternate
-                    // bouncer is showing
-                    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-                        mShadeLogger.d("NSWVC: alt bouncer showing");
-                    }
-                    return true;
-                }
-
-                boolean bouncerShowing;
-                if (DeviceEntryUdfpsRefactor.isEnabled()) {
-                    bouncerShowing = mPrimaryBouncerInteractor.isBouncerShowing()
+                boolean bouncerShowing = mPrimaryBouncerInteractor.isBouncerShowing()
                             || mAlternateBouncerInteractor.isVisibleState();
-                } else {
-                    bouncerShowing = mService.isBouncerShowing();
-                }
                 if (mPanelExpansionInteractor.isFullyExpanded()
                         && !bouncerShowing
                         && !mStatusBarStateController.isDozing()) {
@@ -603,9 +572,6 @@
                 if (mStatusBarStateController.isDozing()) {
                     handled = !mDozeServiceHost.isPulsing();
                 }
-                if (mStatusBarKeyguardViewManager.onTouch(ev)) {
-                    return true;
-                }
                 if (MigrateClocksToBlueprint.isEnabled()) {
                     if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) {
                         // we still want to finish our drag down gesture when locking the screen
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index b7a95e9..0e30f2b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -38,7 +38,7 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 
 import dagger.Lazy;
 
@@ -62,7 +62,7 @@
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final StatusBarStateController mStatusBarStateController;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    private final StatusBarWindowController mStatusBarWindowController;
+    private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
     private final DeviceProvisionedController mDeviceProvisionedController;
 
     private final Lazy<NotificationShadeWindowViewController> mNotifShadeWindowViewController;
@@ -83,7 +83,7 @@
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
-            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowControllerStore statusBarWindowControllerStore,
             DeviceProvisionedController deviceProvisionedController,
             NotificationShadeWindowController notificationShadeWindowController,
             @DisplayId int displayId,
@@ -102,7 +102,7 @@
         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
         mNpvc = shadeViewControllerLazy;
         mStatusBarStateController = statusBarStateController;
-        mStatusBarWindowController = statusBarWindowController;
+        mStatusBarWindowControllerStore = statusBarWindowControllerStore;
         mDeviceProvisionedController = deviceProvisionedController;
         mGutsManager = gutsManager;
         mNotificationShadeWindowController = notificationShadeWindowController;
@@ -315,7 +315,7 @@
 
         // Update the visibility of notification shade and status bar window.
         mNotificationShadeWindowController.setPanelVisible(false);
-        mStatusBarWindowController.setForceStatusBarVisible(false);
+        mStatusBarWindowControllerStore.getDefaultDisplay().setForceStatusBarVisible(false);
 
         // Close any guts that might be visible
         mGutsManager.get().closeAndSaveGuts(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 949d2aa..460bfbb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
@@ -62,17 +63,20 @@
     override val isShadeEnabled: StateFlow<Boolean> =
         disableFlagsRepository.disableFlags
             .map { it.isShadeEnabled() }
+            .flowName("isShadeEnabled")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isQsEnabled: StateFlow<Boolean> =
         disableFlagsRepository.disableFlags
             .map { it.isQuickSettingsEnabled() }
+            .flowName("isQsEnabled")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isAnyFullyExpanded: StateFlow<Boolean> =
         anyExpansion
             .map { it >= 1f }
             .distinctUntilChanged()
+            .flowName("isAnyFullyExpanded")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isShadeFullyExpanded: Flow<Boolean> =
@@ -81,6 +85,7 @@
     override val isShadeAnyExpanded: StateFlow<Boolean> =
         baseShadeInteractor.shadeExpansion
             .map { it > 0 }
+            .flowName("isShadeAnyExpanded")
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isShadeFullyCollapsed: Flow<Boolean> =
@@ -88,6 +93,7 @@
 
     override val isUserInteracting: StateFlow<Boolean> =
         combine(isUserInteractingWithShade, isUserInteractingWithQs) { shade, qs -> shade || qs }
+            .flowName("isUserInteracting")
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isShadeTouchable: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt
index 3113dc4..4bdd367 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.shade.ui.viewmodel
 
-import com.android.app.tracing.coroutines.flow.map
 import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.SwipeDirection
 import com.android.compose.animation.scene.UserAction
@@ -33,6 +32,7 @@
 import dagger.assisted.AssistedInject
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
 
 /**
  * Models the UI state for the user actions that the user can perform to navigate to other scenes.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 1481b73..1ec5357 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -15,7 +15,6 @@
 import com.android.systemui.Dumpable
 import com.android.systemui.ExpandHelper
 import com.android.systemui.Gefingerpoken
-import com.android.systemui.biometrics.UdfpsKeyguardViewControllerLegacy
 import com.android.systemui.classifier.Classifier
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
@@ -90,6 +89,7 @@
     @get:VisibleForTesting
     var fractionToShade: Float = 0f
         private set
+
     private var useSplitShade: Boolean = false
     private lateinit var nsslController: NotificationStackScrollLayoutController
     lateinit var centralSurfaces: CentralSurfaces
@@ -161,9 +161,6 @@
     val distanceUntilShowingPulsingNotifications
         get() = fullTransitionDistance
 
-    /** The udfpsKeyguardViewController if it exists. */
-    var mUdfpsKeyguardViewControllerLegacy: UdfpsKeyguardViewControllerLegacy? = null
-
     /** The touch helper responsible for the drag down animation. */
     val touchHelper =
         DragDownHelper(
@@ -171,7 +168,7 @@
             this,
             naturalScrollingSettingObserver,
             shadeRepository,
-            context
+            context,
         )
 
     private val splitShadeOverScroller: SplitShadeLockScreenOverScroller by lazy {
@@ -448,7 +445,6 @@
 
         val udfpsProgress = MathUtils.saturate(dragDownAmount / udfpsTransitionDistance)
         shadeRepository.setUdfpsTransitionToFullShadeProgress(udfpsProgress)
-        mUdfpsKeyguardViewControllerLegacy?.setTransitionToFullShadeProgress(udfpsProgress)
 
         val statusBarProgress = MathUtils.saturate(dragDownAmount / statusBarTransitionDistance)
         centralSurfaces.setTransitionToFullShadeProgress(statusBarProgress)
@@ -457,7 +453,7 @@
     private fun setDragDownAmountAnimated(
         target: Float,
         delay: Long = 0,
-        endlistener: (() -> Unit)? = null
+        endlistener: (() -> Unit)? = null,
     ) {
         logger.logDragDownAnimation(target)
         val dragDownAnimator = ValueAnimator.ofFloat(dragDownAmount, target)
@@ -553,7 +549,7 @@
     private fun goToLockedShadeInternal(
         expandView: View?,
         animationHandler: ((Long) -> Unit)? = null,
-        cancelAction: Runnable? = null
+        cancelAction: Runnable? = null,
     ) {
         if (!shadeInteractor.isShadeEnabled.value) {
             cancelAction?.run()
@@ -564,10 +560,7 @@
         var entry: NotificationEntry? = null
         if (expandView is ExpandableNotificationRow) {
             entry = expandView.entry
-            entry.setUserExpanded(
-                /* userExpanded= */ true,
-                /* allowChildExpansion= */ true,
-            )
+            entry.setUserExpanded(/* userExpanded= */ true, /* allowChildExpansion= */ true)
             // Indicate that the group expansion is changing at this time -- this way the group
             // and children backgrounds / divider animations will look correct.
             entry.setGroupExpansionChanging(true)
@@ -594,9 +587,7 @@
                 statusBarStateController.setLeaveOpenOnKeyguardHide(false)
                 draggedDownEntry?.apply {
                     setUserLocked(false)
-                    notifyHeightChanged(
-                        /* needsAnimation= */ false,
-                    )
+                    notifyHeightChanged(/* needsAnimation= */ false)
                     draggedDownEntry = null
                 }
                 cancelAction?.run()
@@ -614,9 +605,7 @@
             // This call needs to be after updating the shade state since otherwise
             // the scrimstate resets too early
             if (animationHandler != null) {
-                animationHandler.invoke(
-                    /* delay= */ 0,
-                )
+                animationHandler.invoke(/* delay= */ 0)
             } else {
                 performDefaultGoToFullShadeAnimation(0)
             }
@@ -757,7 +746,7 @@
     private val dragDownCallback: LockscreenShadeTransitionController,
     private val naturalScrollingSettingObserver: NaturalScrollingSettingObserver,
     private val shadeRepository: ShadeRepository,
-    context: Context
+    context: Context,
 ) : Gefingerpoken {
 
     private var dragDownAmountOnStart = 0.0f
@@ -932,7 +921,7 @@
     @VisibleForTesting
     fun cancelChildExpansion(
         child: ExpandableView,
-        animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS
+        animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS,
     ) {
         if (child.actualHeight == child.collapsedHeight) {
             expandCallback.setUserLockedChild(child, false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
index 32d37ae..c019f30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
@@ -22,3 +22,7 @@
 per-file *RemoteInput* = file:notification/OWNERS
 per-file *EmptyShadeView* = set noparent
 per-file *EmptyShadeView* = file:notification/OWNERS
+per-file *Lockscreen* = set noparent
+per-file *Lockscreen* = file:../keyguard/OWNERS
+per-file *Scrim* = set noparent
+per-file *Scrim* = file:../keyguard/OWNERS
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
index be733d4..8ce0dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
@@ -20,7 +20,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.DemoRonChipViewModel
+import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.DemoNotifChipViewModel
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
@@ -31,8 +31,8 @@
 abstract class StatusBarChipsModule {
     @Binds
     @IntoMap
-    @ClassKey(DemoRonChipViewModel::class)
-    abstract fun binds(impl: DemoRonChipViewModel): CoreStartable
+    @ClassKey(DemoNotifChipViewModel::class)
+    abstract fun binds(impl: DemoNotifChipViewModel): CoreStartable
 
     companion object {
         @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModel.kt
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModel.kt
index cce9a16..5fa19dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel
+package com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel
 
 import android.content.pm.PackageManager
 import android.content.pm.PackageManager.NameNotFoundException
@@ -22,7 +22,7 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.ColorsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
@@ -37,25 +37,25 @@
 import kotlinx.coroutines.flow.asStateFlow
 
 /**
- * A view model that will emit demo RON chips (rich ongoing notification chips) from [chip] based on
- * adb commands sent by the user.
+ * A view model that will emit demo promoted ongoing notification chips from [chip] based on adb
+ * commands sent by the user.
  *
  * Example adb commands:
  *
  * To show a chip with the SysUI icon and custom text and color:
  * ```
- * adb shell cmd statusbar demo-ron -p com.android.systemui -t 10min -c "\\#434343"
+ * adb shell cmd statusbar demo-notif -p com.android.systemui -t 10min -c "\\#434343"
  * ```
  *
  * To hide the chip:
  * ```
- * adb shell cmd statusbar demo-ron --hide
+ * adb shell cmd statusbar demo-notif --hide
  * ```
  *
- * See [DemoRonCommand] for more information on the adb command spec.
+ * See [DemoNotifCommand] for more information on the adb command spec.
  */
 @SysUISingleton
-class DemoRonChipViewModel
+class DemoNotifChipViewModel
 @Inject
 constructor(
     private val commandRegistry: CommandRegistry,
@@ -63,19 +63,19 @@
     private val systemClock: SystemClock,
 ) : OngoingActivityChipViewModel, CoreStartable {
     override fun start() {
-        commandRegistry.registerCommand("demo-ron") { DemoRonCommand() }
+        commandRegistry.registerCommand(DEMO_COMMAND_NAME) { DemoNotifCommand() }
     }
 
     private val _chip =
         MutableStateFlow<OngoingActivityChipModel>(OngoingActivityChipModel.Hidden())
     override val chip: StateFlow<OngoingActivityChipModel> = _chip.asStateFlow()
 
-    private inner class DemoRonCommand : ParseableCommand("demo-ron") {
+    private inner class DemoNotifCommand : ParseableCommand(DEMO_COMMAND_NAME) {
         private val packageName: String? by
             param(
                 longName = "packageName",
                 shortName = "p",
-                description = "The package name for the demo RON app",
+                description = "The package name for app \"posting\" the demo notification",
                 valueParser = Type.String,
             )
 
@@ -99,15 +99,12 @@
             )
 
         private val hide by
-            flag(
-                longName = "hide",
-                description = "Hides any existing demo RON chip",
-            )
+            flag(longName = "hide", description = "Hides any existing demo notification chip")
 
         override fun execute(pw: PrintWriter) {
-            if (!StatusBarRonChips.isEnabled) {
+            if (!StatusBarNotifChips.isEnabled) {
                 pw.println(
-                    "Error: com.android.systemui.status_bar_ron_chips must be enabled " +
+                    "Error: com.android.systemui.status_bar_notification_chips must be enabled " +
                         "before using this demo feature"
                 )
                 return
@@ -167,8 +164,12 @@
                 return null
             }
             return OngoingActivityChipModel.ChipIcon.FullColorAppIcon(
-                Icon.Loaded(drawable = iconDrawable, contentDescription = null),
+                Icon.Loaded(drawable = iconDrawable, contentDescription = null)
             )
         }
     }
+
+    companion object {
+        private const val DEMO_COMMAND_NAME = "demo-notif"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/shared/StatusBarRonChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
similarity index 87%
rename from packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/shared/StatusBarRonChips.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
index 4ef1909..47ffbaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/shared/StatusBarRonChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.chips.ron.shared
+package com.android.systemui.statusbar.chips.notification.shared
 
 import com.android.systemui.Flags
 import com.android.systemui.flags.FlagToken
 import com.android.systemui.flags.RefactorFlagUtils
 
-/** Helper for reading or using the status bar RON chips flag state. */
+/** Helper for reading or using the status bar promoted notification chips flag state. */
 @Suppress("NOTHING_TO_INLINE")
-object StatusBarRonChips {
+object StatusBarNotifChips {
     /** The aconfig flag name */
-    const val FLAG_NAME = Flags.FLAG_STATUS_BAR_RON_CHIPS
+    const val FLAG_NAME = Flags.FLAG_STATUS_BAR_NOTIFICATION_CHIPS
 
     /** A token used for dependency declaration */
     val token: FlagToken
@@ -33,7 +33,7 @@
     /** Is the refactor enabled */
     @JvmStatic
     inline val isEnabled
-        get() = Flags.statusBarRonChips()
+        get() = Flags.statusBarNotificationChips()
 
     /**
      * Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
new file mode 100644
index 0000000..6ae9263
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 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.chips.notification.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** A view model for status bar chips for promoted ongoing notifications. */
+@SysUISingleton
+class NotifChipsViewModel
+@Inject
+constructor(activeNotificationsInteractor: ActiveNotificationsInteractor) {
+    /**
+     * A flow modeling the notification chips that should be shown. Emits an empty list if there are
+     * no notifications that should show a status bar chip.
+     */
+    val chips: Flow<List<OngoingActivityChipModel.Shown>> =
+        activeNotificationsInteractor.promotedOngoingNotifications.map { notifications ->
+            notifications.mapNotNull { it.toChipModel() }
+        }
+
+    /**
+     * Converts the notification to the [OngoingActivityChipModel] object. Returns null if the
+     * notification has invalid data such that it can't be displayed as a chip.
+     */
+    private fun ActiveNotificationModel.toChipModel(): OngoingActivityChipModel.Shown? {
+        // TODO(b/364653005): Log error if there's no icon view.
+        val rawIcon = this.statusBarChipIconView ?: return null
+        val icon = OngoingActivityChipModel.ChipIcon.StatusBarView(rawIcon)
+        // TODO(b/364653005): Use the notification color if applicable.
+        val colors = ColorsModel.Themed
+        // TODO(b/364653005): When the chip is clicked, show the HUN.
+        val onClickListener = null
+        return OngoingActivityChipModel.Shown.ShortTimeDelta(
+            icon,
+            colors,
+            time = this.whenTime,
+            onClickListener,
+        )
+        // TODO(b/364653005): If Notification.showWhen = false, don't show the time delta.
+        // TODO(b/364653005): If Notification.whenTime is in the past, show "ago" in the text.
+        // TODO(b/364653005): If Notification.shortCriticalText is set, use that instead of `when`.
+        // TODO(b/364653005): If the app that posted the notification is in the foreground, don't
+        // show that app's chip.
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index 3b1e565..f4462a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -21,13 +21,14 @@
 import android.graphics.drawable.GradientDrawable
 import android.view.View
 import android.view.ViewGroup
+import android.widget.DateTimeView
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.TextView
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
 import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
@@ -42,6 +43,8 @@
         val chipTimeView: ChipChronometer =
             chipView.requireViewById(R.id.ongoing_activity_chip_time)
         val chipTextView: TextView = chipView.requireViewById(R.id.ongoing_activity_chip_text)
+        val chipShortTimeDeltaView: DateTimeView =
+            chipView.requireViewById(R.id.ongoing_activity_chip_short_time_delta)
         val chipBackgroundView: ChipBackgroundContainer =
             chipView.requireViewById(R.id.ongoing_activity_chip_background)
 
@@ -49,13 +52,14 @@
             is OngoingActivityChipModel.Shown -> {
                 // Data
                 setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView)
-                setChipMainContent(chipModel, chipTextView, chipTimeView)
+                setChipMainContent(chipModel, chipTextView, chipTimeView, chipShortTimeDeltaView)
                 chipView.setOnClickListener(chipModel.onClickListener)
                 updateChipPadding(
                     chipModel,
                     chipBackgroundView,
                     chipTextView,
                     chipTimeView,
+                    chipShortTimeDeltaView,
                 )
 
                 // Accessibility
@@ -65,6 +69,7 @@
                 val textColor = chipModel.colors.text(chipContext)
                 chipTimeView.setTextColor(textColor)
                 chipTextView.setTextColor(textColor)
+                chipShortTimeDeltaView.setTextColor(textColor)
                 (chipBackgroundView.background as GradientDrawable).color =
                     chipModel.colors.background(chipContext)
             }
@@ -97,7 +102,7 @@
                 defaultIconView.tintView(iconTint)
             }
             is OngoingActivityChipModel.ChipIcon.FullColorAppIcon -> {
-                StatusBarRonChips.assertInNewMode()
+                StatusBarNotifChips.assertInNewMode()
                 IconViewBinder.bind(icon.impl, defaultIconView)
                 defaultIconView.visibility = View.VISIBLE
                 defaultIconView.untintView()
@@ -161,6 +166,7 @@
         chipModel: OngoingActivityChipModel.Shown,
         chipTextView: TextView,
         chipTimeView: ChipChronometer,
+        chipShortTimeDeltaView: DateTimeView,
     ) {
         when (chipModel) {
             is OngoingActivityChipModel.Shown.Countdown -> {
@@ -168,21 +174,35 @@
                 chipTextView.visibility = View.VISIBLE
 
                 chipTimeView.hide()
+                chipShortTimeDeltaView.visibility = View.GONE
             }
             is OngoingActivityChipModel.Shown.Text -> {
                 chipTextView.text = chipModel.text
                 chipTextView.visibility = View.VISIBLE
 
                 chipTimeView.hide()
+                chipShortTimeDeltaView.visibility = View.GONE
             }
             is OngoingActivityChipModel.Shown.Timer -> {
                 ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
                 chipTimeView.visibility = View.VISIBLE
 
                 chipTextView.visibility = View.GONE
+                chipShortTimeDeltaView.visibility = View.GONE
+            }
+            is OngoingActivityChipModel.Shown.ShortTimeDelta -> {
+                chipShortTimeDeltaView.setTime(chipModel.time)
+                // TODO(b/364653005): DateTimeView's relative time doesn't quite match the format we
+                //  want in the status bar chips.
+                chipShortTimeDeltaView.isShowRelativeTime = true
+                chipShortTimeDeltaView.visibility = View.VISIBLE
+
+                chipTextView.visibility = View.GONE
+                chipTimeView.hide()
             }
             is OngoingActivityChipModel.Shown.IconOnly -> {
                 chipTextView.visibility = View.GONE
+                chipShortTimeDeltaView.visibility = View.GONE
                 chipTimeView.hide()
             }
         }
@@ -200,6 +220,7 @@
         backgroundView: View,
         chipTextView: TextView,
         chipTimeView: ChipChronometer,
+        chipShortTimeDeltaView: DateTimeView,
     ) {
         if (chipModel.icon != null) {
             if (chipModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarView) {
@@ -209,15 +230,18 @@
                 backgroundView.setBackgroundPaddingForEmbeddedPaddingIcon()
                 chipTextView.setTextPaddingForEmbeddedPaddingIcon()
                 chipTimeView.setTextPaddingForEmbeddedPaddingIcon()
+                chipShortTimeDeltaView.setTextPaddingForEmbeddedPaddingIcon()
             } else {
                 backgroundView.setBackgroundPaddingForNormalIcon()
                 chipTextView.setTextPaddingForNormalIcon()
                 chipTimeView.setTextPaddingForNormalIcon()
+                chipShortTimeDeltaView.setTextPaddingForNormalIcon()
             }
         } else {
             backgroundView.setBackgroundPaddingForNoIcon()
             chipTextView.setTextPaddingForNoIcon()
             chipTimeView.setTextPaddingForNoIcon()
+            chipShortTimeDeltaView.setTextPaddingForNoIcon()
         }
     }
 
@@ -258,23 +282,13 @@
             context.resources.getDimensionPixelSize(
                 R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
             )
-        setPaddingRelative(
-            sidePadding,
-            paddingTop,
-            sidePadding,
-            paddingBottom,
-        )
+        setPaddingRelative(sidePadding, paddingTop, sidePadding, paddingBottom)
     }
 
     private fun View.setBackgroundPaddingForNormalIcon() {
         val sidePadding =
             context.resources.getDimensionPixelSize(R.dimen.ongoing_activity_chip_side_padding)
-        setPaddingRelative(
-            sidePadding,
-            paddingTop,
-            sidePadding,
-            paddingBottom,
-        )
+        setPaddingRelative(sidePadding, paddingTop, sidePadding, paddingBottom)
     }
 
     private fun View.setBackgroundPaddingForNoIcon() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index 62622a8..cf07af1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.Flags
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 
 /** Model representing the display of an ongoing activity as a chip in the status bar. */
 sealed class OngoingActivityChipModel {
@@ -79,6 +80,24 @@
         }
 
         /**
+         * The chip shows the time delta between now and [time] in a short format, e.g. "15min" or
+         * "1hr ago".
+         */
+        data class ShortTimeDelta(
+            override val icon: ChipIcon,
+            override val colors: ColorsModel,
+            /** The time of the event that this chip represents. */
+            val time: Long,
+            override val onClickListener: View.OnClickListener?,
+        ) : Shown(icon, colors, onClickListener) {
+            init {
+                StatusBarNotifChips.assertInNewMode()
+            }
+
+            override val logName = "Shown.ShortTimeDelta"
+        }
+
+        /**
          * This chip shows a countdown using [secondsUntilStarted]. Used to inform users that an
          * event is about to start. Typically, a [Countdown] chip will turn into a [Timer] chip.
          */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index 24c1b87..ed32597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.chips.ui.viewmodel
 
-import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.LogBuffer
@@ -24,19 +23,20 @@
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
 import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.CastToOtherDeviceChipViewModel
-import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.DemoRonChipViewModel
-import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
+import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.DemoNotifChipViewModel
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.chips.notification.ui.viewmodel.NotifChipsViewModel
 import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.ScreenRecordChipViewModel
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.util.kotlin.combine
 import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
@@ -55,7 +55,8 @@
     shareToAppChipViewModel: ShareToAppChipViewModel,
     castToOtherDeviceChipViewModel: CastToOtherDeviceChipViewModel,
     callChipViewModel: CallChipViewModel,
-    demoRonChipViewModel: DemoRonChipViewModel,
+    notifChipsViewModel: NotifChipsViewModel,
+    demoNotifChipViewModel: DemoNotifChipViewModel,
     @StatusBarChipsLog private val logger: LogBuffer,
 ) {
     private enum class ChipType {
@@ -63,8 +64,9 @@
         ShareToApp,
         CastToOtherDevice,
         Call,
-        /** A demo of a RON chip (rich ongoing notification chip), used just for testing. */
-        DemoRon,
+        Notification,
+        /** A demo of a notification chip, used just for testing. */
+        DemoNotification,
     }
 
     /** Model that helps us internally track the various chip states from each of the types. */
@@ -85,7 +87,8 @@
             val shareToApp: OngoingActivityChipModel.Hidden,
             val castToOtherDevice: OngoingActivityChipModel.Hidden,
             val call: OngoingActivityChipModel.Hidden,
-            val demoRon: OngoingActivityChipModel.Hidden,
+            val notifs: OngoingActivityChipModel.Hidden,
+            val demoNotif: OngoingActivityChipModel.Hidden,
         ) : InternalChipModel
     }
 
@@ -94,7 +97,8 @@
         val shareToApp: OngoingActivityChipModel = OngoingActivityChipModel.Hidden(),
         val castToOtherDevice: OngoingActivityChipModel = OngoingActivityChipModel.Hidden(),
         val call: OngoingActivityChipModel = OngoingActivityChipModel.Hidden(),
-        val demoRon: OngoingActivityChipModel = OngoingActivityChipModel.Hidden(),
+        val notifs: List<OngoingActivityChipModel.Shown> = emptyList(),
+        val demoNotif: OngoingActivityChipModel = OngoingActivityChipModel.Hidden(),
     )
 
     /** Bundles all the incoming chips into one object to easily pass to various flows. */
@@ -104,8 +108,9 @@
                 shareToAppChipViewModel.chip,
                 castToOtherDeviceChipViewModel.chip,
                 callChipViewModel.chip,
-                demoRonChipViewModel.chip,
-            ) { screenRecord, shareToApp, castToOtherDevice, call, demoRon ->
+                notifChipsViewModel.chips,
+                demoNotifChipViewModel.chip,
+            ) { screenRecord, shareToApp, castToOtherDevice, call, notifs, demoNotif ->
                 logger.log(
                     TAG,
                     LogLevel.INFO,
@@ -121,16 +126,19 @@
                     LogLevel.INFO,
                     {
                         str1 = call.logName
-                        str2 = demoRon.logName
+                        // TODO(b/364653005): Log other information for notification chips.
+                        str2 = notifs.map { it.logName }.toString()
+                        str3 = demoNotif.logName
                     },
-                    { "... > Call=$str1 > DemoRon=$str2" }
+                    { "... > Call=$str1 > Notifs=$str2 > DemoNotif=$str3" },
                 )
                 ChipBundle(
                     screenRecord = screenRecord,
                     shareToApp = shareToApp,
                     castToOtherDevice = castToOtherDevice,
                     call = call,
-                    demoRon = demoRon,
+                    notifs = notifs,
+                    demoNotif = demoNotif,
                 )
             }
             // Some of the chips could have timers in them and we don't want the start time
@@ -189,9 +197,9 @@
      * actually displaying the chip.
      */
     val chips: StateFlow<MultipleOngoingActivityChipsModel> =
-        if (!Flags.statusBarRonChips()) {
-            // Multiple chips are only allowed with RONs. If the flag isn't on, use just the
-            // primary chip.
+        if (!StatusBarNotifChips.isEnabled) {
+            // Multiple chips are only allowed with notification chips. If the flag isn't on, use
+            // just the primary chip.
             primaryChip
                 .map {
                     MultipleOngoingActivityChipsModel(
@@ -199,11 +207,7 @@
                         secondary = OngoingActivityChipModel.Hidden(),
                     )
                 }
-                .stateIn(
-                    scope,
-                    SharingStarted.Lazily,
-                    MultipleOngoingActivityChipsModel(),
-                )
+                .stateIn(scope, SharingStarted.Lazily, MultipleOngoingActivityChipsModel())
         } else {
             internalChips
                 .pairwise(initialValue = DEFAULT_MULTIPLE_INTERNAL_HIDDEN_MODEL)
@@ -212,11 +216,7 @@
                     val correctSecondary = createOutputModel(old.secondary, new.secondary)
                     MultipleOngoingActivityChipsModel(correctPrimary, correctSecondary)
                 }
-                .stateIn(
-                    scope,
-                    SharingStarted.Lazily,
-                    MultipleOngoingActivityChipsModel(),
-                )
+                .stateIn(scope, SharingStarted.Lazily, MultipleOngoingActivityChipsModel())
         }
 
     /** A data class representing the return result of [pickMostImportantChip]. */
@@ -251,7 +251,7 @@
                             // suppress the share-to-app chip to make sure they don't both show.
                             // See b/296461748.
                             shareToApp = OngoingActivityChipModel.Hidden(),
-                        )
+                        ),
                 )
             bundle.shareToApp is OngoingActivityChipModel.Shown ->
                 MostImportantChipResult(
@@ -274,11 +274,19 @@
                     mostImportantChip = InternalChipModel.Shown(ChipType.Call, bundle.call),
                     remainingChips = bundle.copy(call = OngoingActivityChipModel.Hidden()),
                 )
-            bundle.demoRon is OngoingActivityChipModel.Shown -> {
-                StatusBarRonChips.assertInNewMode()
+            bundle.notifs.isNotEmpty() ->
                 MostImportantChipResult(
-                    mostImportantChip = InternalChipModel.Shown(ChipType.DemoRon, bundle.demoRon),
-                    remainingChips = bundle.copy(demoRon = OngoingActivityChipModel.Hidden()),
+                    mostImportantChip =
+                        InternalChipModel.Shown(ChipType.Notification, bundle.notifs.first()),
+                    remainingChips =
+                        bundle.copy(notifs = bundle.notifs.subList(1, bundle.notifs.size)),
+                )
+            bundle.demoNotif is OngoingActivityChipModel.Shown -> {
+                StatusBarNotifChips.assertInNewMode()
+                MostImportantChipResult(
+                    mostImportantChip =
+                        InternalChipModel.Shown(ChipType.DemoNotification, bundle.demoNotif),
+                    remainingChips = bundle.copy(demoNotif = OngoingActivityChipModel.Hidden()),
                 )
             }
             else -> {
@@ -287,7 +295,8 @@
                 check(bundle.shareToApp is OngoingActivityChipModel.Hidden)
                 check(bundle.castToOtherDevice is OngoingActivityChipModel.Hidden)
                 check(bundle.call is OngoingActivityChipModel.Hidden)
-                check(bundle.demoRon is OngoingActivityChipModel.Hidden)
+                check(bundle.notifs.isEmpty())
+                check(bundle.demoNotif is OngoingActivityChipModel.Hidden)
                 MostImportantChipResult(
                     mostImportantChip =
                         InternalChipModel.Hidden(
@@ -295,7 +304,8 @@
                             shareToApp = bundle.shareToApp,
                             castToOtherDevice = bundle.castToOtherDevice,
                             call = bundle.call,
-                            demoRon = bundle.demoRon,
+                            notifs = OngoingActivityChipModel.Hidden(),
+                            demoNotif = bundle.demoNotif,
                         ),
                     // All the chips are already hidden, so no need to filter anything out of the
                     // bundle.
@@ -323,7 +333,8 @@
                 ChipType.ShareToApp -> new.shareToApp
                 ChipType.CastToOtherDevice -> new.castToOtherDevice
                 ChipType.Call -> new.call
-                ChipType.DemoRon -> new.demoRon
+                ChipType.Notification -> new.notifs
+                ChipType.DemoNotification -> new.demoNotif
             }
         } else if (new is InternalChipModel.Shown) {
             // If we have a chip to show, always show it.
@@ -344,7 +355,8 @@
                 shareToApp = OngoingActivityChipModel.Hidden(),
                 castToOtherDevice = OngoingActivityChipModel.Hidden(),
                 call = OngoingActivityChipModel.Hidden(),
-                demoRon = OngoingActivityChipModel.Hidden(),
+                notifs = OngoingActivityChipModel.Hidden(),
+                demoNotif = OngoingActivityChipModel.Hidden(),
             )
 
         private val DEFAULT_MULTIPLE_INTERNAL_HIDDEN_MODEL =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 3ad76b7..7eff812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -18,7 +18,6 @@
 import android.app.Fragment
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.CoreStartable
-import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.fragments.FragmentHostManager
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
@@ -27,9 +26,11 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import java.lang.IllegalStateException
-import javax.inject.Inject
 import javax.inject.Provider
 
 /**
@@ -65,13 +66,17 @@
             statusBarTransitions: PhoneStatusBarTransitions,
         )
     }
+
+    interface Factory {
+        fun create(displayId: Int): StatusBarInitializer
+    }
 }
 
-@SysUISingleton
 class StatusBarInitializerImpl
-@Inject
+@AssistedInject
 constructor(
-    private val windowController: StatusBarWindowController,
+    @Assisted private val displayId: Int,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
     private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
 ) : CoreStartable, StatusBarInitializer {
@@ -106,7 +111,7 @@
 
     private fun doStart() {
         initialized = true
-        windowController.fragmentHostManager
+        statusBarWindowControllerStore.defaultDisplay.fragmentHostManager
             .addTagListener(
                 CollapsedStatusBarFragment.TAG,
                 object : FragmentHostManager.FragmentListener {
@@ -137,4 +142,9 @@
             )
             .commit()
     }
+
+    @AssistedFactory
+    interface Factory : StatusBarInitializer.Factory {
+        override fun create(displayId: Int): StatusBarInitializerImpl
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
new file mode 100644
index 0000000..8d044bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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.core
+
+import android.view.Display
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/** Provides per display instances of [StatusBarInitializer]. */
+interface StatusBarInitializerStore {
+    /**
+     * The instance for the default/main display of the device. For example, on a phone or a tablet,
+     * the default display is the internal/built-in display of the device.
+     *
+     * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
+     */
+    val defaultDisplay: StatusBarInitializer
+
+    /**
+     * Returns an instance for a specific display id.
+     *
+     * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
+     *   displays.
+     */
+    fun forDisplay(displayId: Int): StatusBarInitializer
+}
+
+@SysUISingleton
+class MultiDisplayStatusBarInitializerStore
+@Inject
+constructor(
+    @Background private val backgroundApplicationScope: CoroutineScope,
+    private val factory: StatusBarInitializer.Factory,
+    private val displayRepository: DisplayRepository,
+) : StatusBarInitializerStore, CoreStartable {
+
+    init {
+        StatusBarConnectedDisplays.assertInNewMode()
+    }
+
+    private val perDisplayInitializers = ConcurrentHashMap<Int, StatusBarInitializer>()
+
+    override val defaultDisplay: StatusBarInitializer
+        get() = forDisplay(Display.DEFAULT_DISPLAY)
+
+    override fun forDisplay(displayId: Int): StatusBarInitializer {
+        if (displayRepository.getDisplay(displayId) == null) {
+            throw IllegalArgumentException("Display with id $displayId doesn't exist.")
+        }
+        return perDisplayInitializers.computeIfAbsent(displayId) { factory.create(displayId) }
+    }
+
+    override fun start() {
+        backgroundApplicationScope.launch(
+            CoroutineName("MultiDisplayStatusBarInitializerStore#start")
+        ) {
+            displayRepository.displayRemovalEvent.collect { removedDisplayId ->
+                perDisplayInitializers.remove(removedDisplayId)
+            }
+        }
+    }
+}
+
+@SysUISingleton
+class SingleDisplayStatusBarInitializerStore
+@Inject
+constructor(factory: StatusBarInitializerImpl.Factory) : StatusBarInitializerStore {
+
+    init {
+        StatusBarConnectedDisplays.assertInLegacyMode()
+    }
+
+    private val defaultInstance = factory.create(Display.DEFAULT_DISPLAY)
+
+    override val defaultDisplay: StatusBarInitializer = defaultInstance
+
+    override fun forDisplay(displayId: Int): StatusBarInitializer = defaultDisplay
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
index 8bd990b..d372eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
@@ -36,7 +36,7 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.statusbar.window.data.model.StatusBarWindowState
 import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore
 import com.android.wm.shell.bubbles.Bubbles
@@ -63,8 +63,8 @@
 constructor(
     @Application private val applicationScope: CoroutineScope,
     private val statusBarInitializer: StatusBarInitializer,
-    private val statusBarWindowController: StatusBarWindowController,
     private val statusBarModeRepository: StatusBarModeRepositoryStore,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val demoModeController: DemoModeController,
     private val pluginDependencyProvider: PluginDependencyProvider,
     private val autoHideController: AutoHideController,
@@ -157,7 +157,7 @@
 
     private fun createAndAddWindow() {
         initializeStatusBarFragment()
-        statusBarWindowController.attach()
+        statusBarWindowControllerStore.defaultDisplay.attach()
     }
 
     private fun initializeStatusBarFragment() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index cd1642e..5aad11f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -77,16 +77,6 @@
 
         @Provides
         @SysUISingleton
-        fun defaultStatusBarWindowController(
-            context: Context,
-            viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
-            factory: StatusBarWindowControllerImpl.Factory,
-        ): StatusBarWindowController {
-            return factory.create(context, viewCaptureAwareWindowManager)
-        }
-
-        @Provides
-        @SysUISingleton
         fun windowControllerStore(
             multiDisplayImplLazy: Lazy<MultiDisplayStatusBarWindowControllerStore>,
             singleDisplayImplLazy: Lazy<SingleDisplayStatusBarWindowControllerStore>,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index 118f5f0..bf7e879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -34,7 +34,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.animation.AnimationUtil.Companion.frames
 import javax.inject.Inject
 import kotlin.math.roundToInt
@@ -44,8 +44,8 @@
  */
 class SystemEventChipAnimationController @Inject constructor(
     private val context: Context,
-    private val statusBarWindowController: StatusBarWindowController,
-    private val contentInsetsProvider: StatusBarContentInsetsProvider
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
+    private val contentInsetsProvider: StatusBarContentInsetsProvider,
 ) : SystemStatusAnimationCallback {
 
     private lateinit var animationWindowView: FrameLayout
@@ -244,7 +244,7 @@
         val height = themedContext.resources.getDimensionPixelSize(R.dimen.status_bar_height)
         val lp = FrameLayout.LayoutParams(MATCH_PARENT, height)
         lp.gravity = Gravity.END or Gravity.TOP
-        statusBarWindowController.addViewToWindow(animationWindowView, lp)
+        statusBarWindowControllerStore.defaultDisplay.addViewToWindow(animationWindowView, lp)
         animationWindowView.clipToPadding = false
         animationWindowView.clipChildren = false
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
index f0e60dd..e34f61d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
@@ -23,7 +23,7 @@
 import androidx.core.animation.AnimatorSet
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.Assert
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
@@ -65,7 +65,7 @@
 constructor(
     private val coordinator: SystemEventCoordinator,
     private val chipAnimationController: SystemEventChipAnimationController,
-    private val statusBarWindowController: StatusBarWindowController,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     dumpManager: DumpManager,
     private val systemClock: SystemClock,
     @Application private val coroutineScope: CoroutineScope,
@@ -277,7 +277,7 @@
     private fun runChipAppearAnimation() {
         Assert.isMainThread()
         if (hasPersistentDot) {
-            statusBarWindowController.setForceStatusBarVisible(true)
+            statusBarWindowControllerStore.defaultDisplay.setForceStatusBarVisible(true)
         }
         animationState.value = ANIMATING_IN
 
@@ -311,7 +311,7 @@
                             scheduledEvent.value != null -> ANIMATION_QUEUED
                             else -> IDLE
                         }
-                    statusBarWindowController.setForceStatusBarVisible(false)
+                    statusBarWindowControllerStore.defaultDisplay.setForceStatusBarVisible(false)
                 }
             }
         )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
index 693ae66..ebaa3c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -20,7 +20,7 @@
 import android.view.MotionEvent
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.settings.DisplayTracker
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import javax.inject.Inject
 
 /** A class to detect when a user swipes away the status bar. */
@@ -31,10 +31,11 @@
     context: Context,
     displayTracker: DisplayTracker,
     logger: SwipeUpGestureLogger,
-    private val statusBarWindowController: StatusBarWindowController,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
 ) : SwipeUpGestureHandler(context, displayTracker, logger, loggerTag = LOGGER_TAG) {
     override fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean {
         // Gesture starts just below the status bar
+        val statusBarWindowController = statusBarWindowControllerStore.defaultDisplay
         return ev.y >= statusBarWindowController.statusBarHeight &&
             ev.y <= 3 * statusBarWindowController.statusBarHeight
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
index 9b382e6..697a6ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
@@ -17,6 +17,7 @@
 
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.collection.render.NotifStats
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel
@@ -26,6 +27,7 @@
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 
@@ -74,6 +76,17 @@
     val allNotificationsCountValue: Int
         get() = repository.activeNotifications.value.individuals.size
 
+    /** The notifications that are promoted and ongoing. Sorted by priority order. */
+    val promotedOngoingNotifications: Flow<List<ActiveNotificationModel>> =
+        if (StatusBarNotifChips.isEnabled) {
+            // TODO(b/364653005): Filter all the notifications down to just the promoted ones.
+            // TODO(b/364653005): [ongoingCallNotification] should be incorporated into this flow
+            // instead of being separate.
+            topLevelRepresentativeNotifications
+        } else {
+            flowOf(emptyList())
+        }
+
     /**
      * The priority ongoing call notification, or null if there is no ongoing call.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
index 695e088..fbec640 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.icu.text.MessageFormat
-import com.android.app.tracing.coroutines.flow.flowOn
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.modes.shared.ModesUi
@@ -40,6 +39,7 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 560028c..d538f52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -449,7 +449,7 @@
                 }
 
                 // We need to reset the View state, even if the animation was cancelled
-                onAppearAnimationFinished(isAppearing);
+                onAppearAnimationFinished(isAppearing, /* cancelled = */ !mRunWithoutInterruptions);
 
                 if (mRunWithoutInterruptions) {
                     InteractionJankMonitor.getInstance().end(getCujType(isAppearing));
@@ -463,6 +463,7 @@
                 if (onStartedRunnable != null) {
                     onStartedRunnable.run();
                 }
+                onAppearAnimationStarted(isAppearing);
                 mRunWithoutInterruptions = true;
                 Configuration.Builder builder = Configuration.Builder
                         .withView(getCujType(isAppearing), ActivatableNotificationView.this);
@@ -486,6 +487,8 @@
                 frameTimeNanos -> {
                     if (mAppearAnimator == cachedAnimator) {
                         mAppearAnimator.start();
+                    } else {
+                        onAppearAnimationSkipped(isAppearing);
                     }
                 }, delay);
     }
@@ -502,7 +505,13 @@
         }
     }
 
-    protected void onAppearAnimationFinished(boolean wasAppearing) {
+    protected void onAppearAnimationStarted(boolean isAppear) {
+    }
+
+    protected void onAppearAnimationSkipped(boolean isAppear) {
+    }
+
+    protected void onAppearAnimationFinished(boolean wasAppearing, boolean cancelled) {
     }
 
     private void cancelAppearAnimation() {
@@ -830,4 +839,13 @@
             });
         }
     }
+
+    protected void dumpAppearAnimationProperties(IndentingPrintWriter pw, String[] args) {
+        pw.print("AppearAnimation: ");
+        pw.print("mDrawingAppearAnimation", mDrawingAppearAnimation);
+        pw.print("mAppearAnimationFraction", mAppearAnimationFraction);
+        pw.print("mIsHeadsUpAnimation", mIsHeadsUpAnimation);
+        pw.print("mTargetPoint", mTargetPoint);
+        pw.println();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 49153d1..38e6609 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1835,6 +1835,25 @@
         void logSkipResetAllContentAlphas(
                 NotificationEntry entry
         );
+
+        /** Called when we start an appear animation. */
+        void logStartAppearAnimation(NotificationEntry entry, boolean isAppear);
+
+        /** Called when we cancel the running appear animation. */
+        void logCancelAppearDrawing(NotificationEntry entry, boolean wasDrawing);
+
+        /** Called when the animator of the appear animation is started. */
+        void logAppearAnimationStarted(NotificationEntry entry, boolean isAppear);
+
+        /** Called when we prepared an appear animation, but the animator was never started. */
+        void logAppearAnimationSkipped(NotificationEntry entry, boolean isAppear);
+
+        /** Called when the animator of the appear animation is finished. */
+        void logAppearAnimationFinished(
+                NotificationEntry entry,
+                boolean isAppear,
+                boolean cancelled
+        );
     }
 
     /**
@@ -3165,6 +3184,13 @@
     }
 
     @Override
+    public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear,
+            Runnable onFinishRunnable) {
+        mLogger.logStartAppearAnimation(getEntry(), /* isAppear = */ true);
+        super.performAddAnimation(delay, duration, isHeadsUpAppear, onFinishRunnable);
+    }
+
+    @Override
     public long performRemoveAnimation(
             long duration,
             long delay,
@@ -3173,6 +3199,7 @@
             Runnable onStartedRunnable,
             Runnable onFinishedRunnable,
             AnimatorListenerAdapter animationListener, ClipSide clipSide) {
+        mLogger.logStartAppearAnimation(getEntry(), /* isAppear = */ false);
         if (mMenuRow != null && mMenuRow.isMenuVisible()) {
             Animator anim = getTranslateViewAnimator(0f, null /* listener */);
             if (anim != null) {
@@ -3201,8 +3228,25 @@
     }
 
     @Override
-    protected void onAppearAnimationFinished(boolean wasAppearing) {
-        super.onAppearAnimationFinished(wasAppearing);
+    protected void onAppearAnimationStarted(boolean isAppear) {
+        mLogger.logAppearAnimationStarted(getEntry(), /* isAppear = */ isAppear);
+        super.onAppearAnimationStarted(isAppear);
+    }
+
+    @Override
+    protected void onAppearAnimationSkipped(boolean isAppear) {
+        mLogger.logAppearAnimationSkipped(getEntry(),  /* isAppear = */ isAppear);
+        super.onAppearAnimationSkipped(isAppear);
+    }
+
+    @Override
+    protected void onAppearAnimationFinished(boolean wasAppearing, boolean cancelled) {
+        mLogger.logAppearAnimationFinished(
+                /* entry = */ getEntry(),
+                /* isAppear = */ wasAppearing,
+                /* cancelled = */ cancelled
+        );
+        super.onAppearAnimationFinished(wasAppearing, cancelled);
         if (wasAppearing) {
             // During the animation the visible view might have changed, so let's make sure all
             // alphas are reset
@@ -3218,6 +3262,12 @@
     }
 
     @Override
+    public void cancelAppearDrawing() {
+        mLogger.logCancelAppearDrawing(getEntry(), isDrawingAppearAnimation());
+        super.cancelAppearDrawing();
+    }
+
+    @Override
     public void resetAllContentAlphas() {
         mLogger.logResetAllContentAlphas(getEntry());
         mPrivateLayout.setAlpha(1f);
@@ -3883,6 +3933,7 @@
                 dumpHeights(pw);
             }
             showingLayout.dump(pw, args);
+            dumpAppearAnimationProperties(pw, args);
             dumpCustomOutline(pw, args);
             dumpClipping(pw, args);
             if (getViewState() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c31a2cb..23a2fac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -209,6 +209,32 @@
                 ) {
                     mLogBufferLogger.logSkipResetAllContentAlphas(entry);
                 }
+
+                @Override
+                public void logStartAppearAnimation(NotificationEntry entry, boolean isAppear) {
+                    mLogBufferLogger.logStartAppearAnimation(entry, isAppear);
+                }
+
+                @Override
+                public void logCancelAppearDrawing(NotificationEntry entry, boolean wasDrawing) {
+                    mLogBufferLogger.logCancelAppearDrawing(entry, wasDrawing);
+                }
+
+                @Override
+                public void logAppearAnimationStarted(NotificationEntry entry, boolean isAppear) {
+                    mLogBufferLogger.logAppearAnimationStarted(entry, isAppear);
+                }
+
+                @Override
+                public void logAppearAnimationSkipped(NotificationEntry entry, boolean isAppear) {
+                    mLogBufferLogger.logAppearAnimationSkipped(entry, isAppear);
+                }
+
+                @Override
+                public void logAppearAnimationFinished(NotificationEntry entry, boolean isAppear,
+                        boolean cancelled) {
+                    mLogBufferLogger.logAppearAnimationFinished(entry, isAppear, cancelled);
+                }
             };
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt
index b90aa10..71f9c07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt
@@ -19,6 +19,7 @@
 import android.widget.flags.Flags.notifLinearlayoutOptimized
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing
 import javax.inject.Inject
 import javax.inject.Provider
@@ -35,6 +36,7 @@
     bigPictureLayoutInflaterFactory: BigPictureLayoutInflaterFactory,
     optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory,
     notificationViewFlipperFactory: Provider<NotificationViewFlipperFactory>,
+    notificationRowIconViewInflaterFactory: NotificationRowIconViewInflaterFactory,
 ) : NotifRemoteViewsFactoryContainer {
     override val factories: Set<NotifRemoteViewsFactory> = buildSet {
         add(precomputedTextViewFactory)
@@ -47,5 +49,8 @@
         if (NotificationViewFlipperPausing.isEnabled) {
             add(notificationViewFlipperFactory.get())
         }
+        if (android.app.Flags.notificationsRedesignAppIcons()) {
+            add(notificationRowIconViewInflaterFactory)
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index e10fd8f..41abac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -342,7 +342,7 @@
      * Cancel any pending content view frees from {@link #freeNotificationView} for the provided
      * content views.
      *
-     * @param row top level notification row containing the content views
+     * @param row          top level notification row containing the content views
      * @param contentViews content views to cancel pending frees on
      */
     private void cancelContentViewFrees(
@@ -478,6 +478,13 @@
                 notifLayoutInflaterFactoryProvider.provide(row, FLAG_CONTENT_VIEW_HEADS_UP));
         setRemoteViewsInflaterFactory(result.newPublicView,
                 notifLayoutInflaterFactoryProvider.provide(row, FLAG_CONTENT_VIEW_PUBLIC));
+        if (android.app.Flags.notificationsRedesignAppIcons()) {
+            setRemoteViewsInflaterFactory(result.mNewGroupHeaderView,
+                    notifLayoutInflaterFactoryProvider.provide(row, FLAG_GROUP_SUMMARY_HEADER));
+            setRemoteViewsInflaterFactory(result.mNewMinimizedGroupHeaderView,
+                    notifLayoutInflaterFactoryProvider.provide(row,
+                            FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER));
+        }
     }
 
     private static void setRemoteViewsInflaterFactory(RemoteViews remoteViews,
@@ -516,6 +523,7 @@
                     logger.logAsyncTaskProgress(entry, "contracted view applied");
                     result.inflatedContentView = v;
                 }
+
                 @Override
                 public RemoteViews getRemoteView() {
                     return result.newContentView;
@@ -1406,6 +1414,7 @@
     @VisibleForTesting
     abstract static class ApplyCallback {
         public abstract void setResultView(View v);
+
         public abstract RemoteViews getRemoteView();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
index b1e9032..6e78f56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
@@ -30,7 +30,7 @@
 @Inject
 constructor(
     @NotificationLog private val buffer: LogBuffer,
-    @NotificationRenderLog private val notificationRenderBuffer: LogBuffer
+    @NotificationRenderLog private val notificationRenderBuffer: LogBuffer,
 ) {
     fun logKeepInParentChildDetached(child: NotificationEntry, oldParent: NotificationEntry?) {
         buffer.log(
@@ -40,7 +40,7 @@
                 str1 = child.logKey
                 str2 = oldParent.logKey
             },
-            { "Detach child $str1 kept in parent $str2" }
+            { "Detach child $str1 kept in parent $str2" },
         )
     }
 
@@ -52,13 +52,13 @@
                 str1 = child.logKey
                 str2 = newParent.logKey
             },
-            { "Skipping to attach $str1 to $str2, because it still flagged to keep in parent" }
+            { "Skipping to attach $str1 to $str2, because it still flagged to keep in parent" },
         )
     }
 
     fun logRemoveTransientFromContainer(
         childEntry: NotificationEntry,
-        containerEntry: NotificationEntry
+        containerEntry: NotificationEntry,
     ) {
         notificationRenderBuffer.log(
             TAG,
@@ -67,25 +67,20 @@
                 str1 = childEntry.logKey
                 str2 = containerEntry.logKey
             },
-            { "RemoveTransientRow from ChildrenContainer: childKey: $str1 -- containerKey: $str2" }
+            { "RemoveTransientRow from ChildrenContainer: childKey: $str1 -- containerKey: $str2" },
         )
     }
 
-    fun logRemoveTransientFromNssl(
-        childEntry: NotificationEntry,
-    ) {
+    fun logRemoveTransientFromNssl(childEntry: NotificationEntry) {
         notificationRenderBuffer.log(
             TAG,
             LogLevel.INFO,
             { str1 = childEntry.logKey },
-            { "RemoveTransientRow from Nssl: childKey: $str1" }
+            { "RemoveTransientRow from Nssl: childKey: $str1" },
         )
     }
 
-    fun logRemoveTransientFromViewGroup(
-        childEntry: NotificationEntry,
-        containerView: ViewGroup,
-    ) {
+    fun logRemoveTransientFromViewGroup(childEntry: NotificationEntry, containerView: ViewGroup) {
         notificationRenderBuffer.log(
             TAG,
             LogLevel.WARNING,
@@ -93,14 +88,14 @@
                 str1 = childEntry.logKey
                 str2 = containerView.toString()
             },
-            { "RemoveTransientRow from other ViewGroup: childKey: $str1 -- ViewGroup: $str2" }
+            { "RemoveTransientRow from other ViewGroup: childKey: $str1 -- ViewGroup: $str2" },
         )
     }
 
     fun logAddTransientRow(
         childEntry: NotificationEntry,
         containerEntry: NotificationEntry,
-        index: Int
+        index: Int,
     ) {
         notificationRenderBuffer.log(
             TAG,
@@ -110,14 +105,11 @@
                 str2 = containerEntry.logKey
                 int1 = index
             },
-            { "addTransientRow to row: childKey: $str1 -- containerKey: $str2 -- index: $int1" }
+            { "addTransientRow to row: childKey: $str1 -- containerKey: $str2 -- index: $int1" },
         )
     }
 
-    fun logRemoveTransientRow(
-        childEntry: NotificationEntry,
-        containerEntry: NotificationEntry,
-    ) {
+    fun logRemoveTransientRow(childEntry: NotificationEntry, containerEntry: NotificationEntry) {
         notificationRenderBuffer.log(
             TAG,
             LogLevel.ERROR,
@@ -125,7 +117,7 @@
                 str1 = childEntry.logKey
                 str2 = containerEntry.logKey
             },
-            { "removeTransientRow from row: childKey: $str1 -- containerKey: $str2" }
+            { "removeTransientRow from row: childKey: $str1 -- containerKey: $str2" },
         )
     }
 
@@ -134,7 +126,7 @@
             TAG,
             LogLevel.INFO,
             { str1 = entry.logKey },
-            { "resetAllContentAlphas: $str1" }
+            { "resetAllContentAlphas: $str1" },
         )
     }
 
@@ -143,7 +135,72 @@
             TAG,
             LogLevel.INFO,
             { str1 = entry.logKey },
-            { "Skip resetAllContentAlphas: $str1" }
+            { "Skip resetAllContentAlphas: $str1" },
+        )
+    }
+
+    fun logStartAppearAnimation(entry: NotificationEntry, isAppear: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                bool1 = isAppear
+            },
+            { "startAppearAnimation childKey: $str1 isAppear:$bool1" },
+        )
+    }
+
+    fun logCancelAppearDrawing(entry: NotificationEntry, wasDrawing: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.WARNING,
+            {
+                str1 = entry.logKey
+                bool1 = wasDrawing
+            },
+            { "cancelAppearDrawing childKey: $str1 wasDrawing:$bool1" },
+        )
+    }
+
+    fun logAppearAnimationStarted(entry: NotificationEntry, isAppear: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                bool1 = isAppear
+            },
+            { "onAppearAnimationStarted childKey: $str1 isAppear:$bool1" },
+        )
+    }
+
+    fun logAppearAnimationSkipped(entry: NotificationEntry, isAppear: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.WARNING,
+            {
+                str1 = entry.logKey
+                bool1 = isAppear
+            },
+            { "Skipped an appear animation childKey: $str1 isAppear:$bool1" },
+        )
+    }
+
+    fun logAppearAnimationFinished(
+        entry: NotificationEntry,
+        isAppear: Boolean,
+        cancelled: Boolean,
+    ) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                bool1 = isAppear
+                bool2 = cancelled
+            },
+            { "onAppearAnimationFinished childKey: $str1 isAppear:$bool1 cancelled:$bool2" },
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
index 84f2f66..4feb78a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -17,6 +17,8 @@
 package com.android.systemui.statusbar.notification.row;
 
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.notification.row.icon.AppIconProviderModule;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProviderModule;
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor;
 
 import dagger.Binds;
@@ -28,7 +30,7 @@
 /**
  * Dagger Module containing notification row and view inflation implementations.
  */
-@Module
+@Module(includes = {AppIconProviderModule.class, NotificationIconStyleProviderModule.class})
 public abstract class NotificationRowModule {
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
new file mode 100644
index 0000000..24b5cf1a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.app.ActivityManager
+import android.app.Flags
+import android.content.Context
+import android.content.pm.PackageManager.NameNotFoundException
+import android.graphics.Color
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.util.Log
+import com.android.internal.R
+import com.android.launcher3.icons.BaseIconFactory
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import javax.inject.Provider
+
+/** A provider used to cache and fetch app icons used by notifications. */
+interface AppIconProvider {
+    @Throws(NameNotFoundException::class)
+    fun getOrFetchAppIcon(packageName: String, context: Context): Drawable
+}
+
+@SysUISingleton
+class AppIconProviderImpl @Inject constructor(private val sysuiContext: Context) : AppIconProvider {
+    private val iconFactory: BaseIconFactory
+        get() {
+            val isLowRam = ActivityManager.isLowRamDeviceStatic()
+            val res = sysuiContext.resources
+            val iconSize: Int =
+                res.getDimensionPixelSize(
+                    if (isLowRam) R.dimen.notification_small_icon_size_low_ram
+                    else R.dimen.notification_small_icon_size
+                )
+            return BaseIconFactory(sysuiContext, res.configuration.densityDpi, iconSize)
+        }
+
+    override fun getOrFetchAppIcon(packageName: String, context: Context): Drawable {
+        val icon = context.packageManager.getApplicationIcon(packageName)
+        return BitmapDrawable(
+            context.resources,
+            iconFactory.createScaledBitmap(icon, BaseIconFactory.MODE_HARDWARE),
+        )
+    }
+}
+
+class NoOpIconProvider : AppIconProvider {
+    companion object {
+        const val TAG = "NoOpIconProvider"
+    }
+
+    override fun getOrFetchAppIcon(packageName: String, context: Context): Drawable {
+        Log.wtf(TAG, "NoOpIconProvider should not be used anywhere.")
+        return ColorDrawable(Color.WHITE)
+    }
+}
+
+@Module
+class AppIconProviderModule {
+    @Provides
+    @SysUISingleton
+    fun provideImpl(realImpl: Provider<AppIconProviderImpl>): AppIconProvider =
+        if (Flags.notificationsRedesignAppIcons()) {
+            realImpl.get()
+        } else {
+            NoOpIconProvider()
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationIconStyleProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationIconStyleProvider.kt
new file mode 100644
index 0000000..165c1a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationIconStyleProvider.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.annotation.WorkerThread
+import android.app.Flags
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.service.notification.StatusBarNotification
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import javax.inject.Provider
+
+/**
+ * A provider used to cache and fetch information about which icon should be displayed by
+ * notifications.
+ */
+interface NotificationIconStyleProvider {
+    @WorkerThread
+    fun shouldShowAppIcon(notification: StatusBarNotification, context: Context): Boolean
+}
+
+@SysUISingleton
+class NotificationIconStyleProviderImpl @Inject constructor() : NotificationIconStyleProvider {
+    override fun shouldShowAppIcon(notification: StatusBarNotification, context: Context): Boolean {
+        val packageContext = notification.getPackageContext(context)
+        return !belongsToHeadlessSystemApp(packageContext)
+    }
+
+    @WorkerThread
+    private fun belongsToHeadlessSystemApp(context: Context): Boolean {
+        val info = context.applicationInfo
+        if (info != null) {
+            if ((info.flags and ApplicationInfo.FLAG_SYSTEM) == 0) {
+                // It's not a system app at all.
+                return false
+            } else {
+                // If there's no launch intent, it's probably a headless app.
+                val pm = context.packageManager
+                return (pm.getLaunchIntentForPackage(info.packageName) == null)
+            }
+        } else {
+            // If for some reason we don't have the app info, we don't know; best assume it's
+            // not a system app.
+            return false
+        }
+    }
+}
+
+class NoOpIconStyleProvider : NotificationIconStyleProvider {
+    companion object {
+        const val TAG = "NoOpIconStyleProvider"
+    }
+
+    override fun shouldShowAppIcon(notification: StatusBarNotification, context: Context): Boolean {
+        Log.wtf(TAG, "NoOpIconStyleProvider should not be used anywhere.")
+        return true
+    }
+}
+
+@Module
+class NotificationIconStyleProviderModule {
+    @Provides
+    @SysUISingleton
+    fun provideImpl(
+        realImpl: Provider<NotificationIconStyleProviderImpl>
+    ): NotificationIconStyleProvider =
+        if (Flags.notificationsRedesignAppIcons()) {
+            realImpl.get()
+        } else {
+            NoOpIconStyleProvider()
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
new file mode 100644
index 0000000..79defd2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.View
+import com.android.internal.widget.NotificationRowIconView
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotifRemoteViewsFactory
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder
+import javax.inject.Inject
+
+/**
+ * A factory which owns the construction of any NotificationRowIconView inside of Notifications in
+ * SystemUI. This allows overriding the small icon with the app icon in notifications.
+ */
+class NotificationRowIconViewInflaterFactory
+@Inject
+constructor(
+    private val appIconProvider: AppIconProvider,
+    private val iconStyleProvider: NotificationIconStyleProvider,
+) : NotifRemoteViewsFactory {
+    override fun instantiate(
+        row: ExpandableNotificationRow,
+        @NotificationRowContentBinder.InflationFlag layoutType: Int,
+        parent: View?,
+        name: String,
+        context: Context,
+        attrs: AttributeSet,
+    ): View? {
+        return when (name) {
+            NotificationRowIconView::class.java.name ->
+                NotificationRowIconView(context, attrs).also { view ->
+                    val sbn = row.entry.sbn
+                    view.setIconProvider(
+                        object : NotificationRowIconView.NotificationIconProvider {
+                            override fun shouldShowAppIcon(): Boolean {
+                                return iconStyleProvider.shouldShowAppIcon(row.entry.sbn, context)
+                            }
+
+                            override fun getAppIcon(): Drawable {
+                                return appIconProvider.getOrFetchAppIcon(sbn.packageName, context)
+                            }
+                        }
+                    )
+                }
+            else -> null
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 00c5c40..f3437b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -2098,8 +2098,13 @@
     }
 
     class TouchHandler implements Gefingerpoken {
+        private boolean mSwipeWantsIt = false;
+
         @Override
         public boolean onInterceptTouchEvent(MotionEvent ev) {
+            // Reset on each call to intercept, and share swipe state with onTouchEvent()
+            // below when this method returns true.
+            mSwipeWantsIt = false;
             mView.initDownStates(ev);
             mView.handleEmptySpaceClick(ev);
 
@@ -2126,17 +2131,16 @@
                     mView.startDraggingOnHun();
                 }
             }
-            boolean swipeWantsIt = false;
             if (mLongPressedView == null && !mView.isBeingDragged()
                     && !mView.isExpandingNotification()
                     && !mView.getExpandedInThisMotion()
                     && !mView.getOnlyScrollingInThisMotion()
                     && !mView.getDisallowDismissInThisMotion()) {
-                swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+                mSwipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
             }
             // Check if we need to clear any snooze leavebehinds
             boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
-            if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+            if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !mSwipeWantsIt &&
                     !expandWantsIt && !scrollWantsIt) {
                 mView.setCheckForLeaveBehind(false);
                 mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
@@ -2155,7 +2159,8 @@
                     && ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
                 mJankMonitor.begin(mView, CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
             }
-            return swipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt || hunWantsIt;
+            return mSwipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt ||
+                    hunWantsIt;
         }
 
         @Override
@@ -2192,7 +2197,7 @@
                     }
                 }
             }
-            boolean horizontalSwipeWantsIt = false;
+            boolean horizontalSwipeWantsIt = mSwipeWantsIt;
             boolean scrollerWantsIt = false;
             // NOTE: the order of these is important. If reversed, onScrollTouch will reset on an
             // UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes.
@@ -2201,7 +2206,7 @@
                     && !mView.getExpandedInThisMotion()
                     && !onlyScrollingInThisMotion
                     && !mView.getDisallowDismissInThisMotion()) {
-                horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+                mSwipeHelper.onTouchEvent(ev);
             }
             if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
                     && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 87d70ba..fb42ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -17,7 +17,8 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewbinder
 
 import android.util.Log
-import com.android.app.tracing.coroutines.flow.filter
+import com.android.app.tracing.coroutines.flow.collectTraced
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.common.ui.view.onLayoutChanged
 import com.android.systemui.dagger.SysUISingleton
@@ -37,7 +38,6 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.launch
 
 /** Binds the [NotificationScrollView]. */
 @SysUISingleton
@@ -79,39 +79,39 @@
             launch {
                 viewModel
                     .shadeScrimShape(cornerRadius = scrimRadius, viewLeftOffset = viewLeftOffset)
-                    .collect { view.setScrimClippingShape(it) }
+                    .collectTraced { view.setScrimClippingShape(it) }
             }
 
-            launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } }
-            launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
+            launch { viewModel.maxAlpha.collectTraced { view.setMaxAlpha(it) } }
+            launch { viewModel.scrolledToTop.collectTraced { view.setScrolledToTop(it) } }
             launch {
-                viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) }
+                viewModel.expandFraction.collectTraced { view.setExpandFraction(it.coerceIn(0f, 1f)) }
             }
-            launch { viewModel.qsExpandFraction.collect { view.setQsExpandFraction(it) } }
+            launch { viewModel.qsExpandFraction.collectTraced { view.setQsExpandFraction(it) } }
             launch {
-                viewModel.isShowingStackOnLockscreen.collect {
+                viewModel.isShowingStackOnLockscreen.collectTraced {
                     view.setShowingStackOnLockscreen(it)
                 }
             }
             launch {
-                viewModel.alphaForLockscreenFadeIn.collect { view.setAlphaForLockscreenFadeIn(it) }
+                viewModel.alphaForLockscreenFadeIn.collectTraced { view.setAlphaForLockscreenFadeIn(it) }
             }
-            launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } }
-            launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } }
+            launch { viewModel.isScrollable.collectTraced { view.setScrollingEnabled(it) } }
+            launch { viewModel.isDozing.collectTraced { isDozing -> view.setDozing(isDozing) } }
             launch {
-                viewModel.isPulsing.collect { isPulsing ->
+                viewModel.isPulsing.collectTraced { isPulsing ->
                     view.setPulsing(isPulsing, viewModel.shouldAnimatePulse.value)
                 }
             }
             launch {
                 viewModel.shouldResetStackTop
                     .filter { it }
-                    .collect { view.setStackTop(-(view.getHeadsUpInset().toFloat())) }
+                    .collectTraced { view.setStackTop(-(view.getHeadsUpInset().toFloat())) }
             }
             launch {
-                viewModel.shouldCloseGuts.filter { it }.collect { view.closeGutsOnSceneTouch() }
+                viewModel.shouldCloseGuts.filter { it }.collectTraced { view.closeGutsOnSceneTouch() }
             }
-            launch { viewModel.suppressHeightUpdates.collect { view.suppressHeightUpdates(it) } }
+            launch { viewModel.suppressHeightUpdates.collectTraced { view.suppressHeightUpdates(it) } }
 
             launchAndDispose {
                 view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index f39af18..878ae91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -20,6 +20,7 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.dagger.SysUISingleton
@@ -158,6 +159,7 @@
             ) { shadeExpansion, qsExpansion ->
                 shadeExpansion || qsExpansion
             }
+            .flowName("isAnyExpanded")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -175,6 +177,7 @@
                 isAnyExpanded ->
                 isShadeLocked && isAnyExpanded
             }
+            .flowName("isShadeLocked")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -227,6 +230,7 @@
                 ),
                 keyguardTransitionInteractor.transitionValue(LOCKSCREEN).map { it > 0f },
             )
+            .flowName("isOnLockscreen")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -239,6 +243,7 @@
         combine(isOnLockscreen, isAnyExpanded) { isKeyguard, isAnyExpanded ->
                 isKeyguard && !isAnyExpanded
             }
+            .flowName("isOnLockscreenWithoutShade")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -274,6 +279,7 @@
         combine(isOnGlanceableHub, isAnyExpanded) { isGlanceableHub, isAnyExpanded ->
                 isGlanceableHub && !isAnyExpanded
             }
+            .flowName("isOnGlanceableHubWithoutShade")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -288,6 +294,7 @@
                 isAnyExpanded ->
                 isDreaming && !isAnyExpanded
             }
+            .flowName("isDreamingWithoutShade")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -345,6 +352,7 @@
                     }
                 }
             }
+            .flowName("shadeCollapseFadeIn")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
@@ -382,6 +390,7 @@
                     bounds.copy(top = top, isAnimated = animate)
                 }
             }
+            .flowName("bounds")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Lazily,
@@ -495,6 +504,7 @@
         // flatMapLatest below, the last value gets emitted, to avoid the randomness of `merge`.
         val alphaForTransitionsAndShade =
             merge(alphaForTransitions(viewState), alphaForShadeAndQsExpansion)
+                .flowName("alphaForTransitionsAndShade")
                 .stateIn(
                     // Use view-level scope instead of ApplicationScope, to prevent collection that
                     // never stops
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
index 5b37468..d1338ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
@@ -58,7 +58,7 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.kotlin.getOrNull
@@ -93,7 +93,7 @@
     @Main private val mainExecutor: DelayableExecutor,
     private val shadeControllerLazy: Lazy<ShadeController>,
     private val communalSceneInteractor: CommunalSceneInteractor,
-    private val statusBarWindowController: StatusBarWindowController,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
     private val shadeAnimationInteractor: ShadeAnimationInteractor,
     private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>,
@@ -562,7 +562,7 @@
         }
         val rootView = animationController.transitionContainer.rootView
         val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> =
-            statusBarWindowController.wrapAnimationControllerIfInStatusBar(
+            statusBarWindowControllerStore.defaultDisplay.wrapAnimationControllerIfInStatusBar(
                 rootView,
                 animationController
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7e5b455..3d7cd9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -128,7 +128,6 @@
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.emergency.EmergencyGesture;
 import com.android.systemui.emergency.EmergencyGestureModule.EmergencyGestureIntentFactory;
 import com.android.systemui.flags.FeatureFlags;
@@ -226,7 +225,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
 import com.android.systemui.util.DumpUtilsKt;
@@ -372,7 +371,7 @@
     @WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final StatusBarInitializer mStatusBarInitializer;
-    private final StatusBarWindowController mStatusBarWindowController;
+    private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
     private final StatusBarModeRepositoryStore mStatusBarModeRepository;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @VisibleForTesting
@@ -610,7 +609,7 @@
             LightBarController lightBarController,
             AutoHideController autoHideController,
             StatusBarInitializer statusBarInitializer,
-            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowControllerStore statusBarWindowControllerStore,
             StatusBarWindowStateController statusBarWindowStateController,
             StatusBarModeRepositoryStore statusBarModeRepository,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -716,7 +715,7 @@
         mLightBarController = lightBarController;
         mAutoHideController = autoHideController;
         mStatusBarInitializer = statusBarInitializer;
-        mStatusBarWindowController = statusBarWindowController;
+        mStatusBarWindowControllerStore = statusBarWindowControllerStore;
         mStatusBarModeRepository = statusBarModeRepository;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mPulseExpansionHandler = pulseExpansionHandler;
@@ -1894,7 +1893,7 @@
         // When the StatusBarSimpleFragment flag is enabled, this logic will be done in
         // StatusBarOrchestrator
         if (!StatusBarSimpleFragment.isEnabled()) {
-            mStatusBarWindowController.attach();
+            mStatusBarWindowControllerStore.getDefaultDisplay().attach();
         }
     }
 
@@ -2825,23 +2824,13 @@
         mScrimController.setExpansionAffectsAlpha(!unlocking);
 
         if (mAlternateBouncerInteractor.isVisibleState()) {
-            if (DeviceEntryUdfpsRefactor.isEnabled()) {
-                if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
-                        && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
-                        || mTransitionToFullShadeProgress > 0f)) {
-                    // Assume scrim state for shade is already correct and do nothing
-                } else {
-                    // Safeguard which prevents the scrim from being stuck in the wrong state
-                    mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
-                }
+            if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
+                    && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
+                    || mTransitionToFullShadeProgress > 0f)) {
+                // Assume scrim state for shade is already correct and do nothing
             } else {
-                if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
-                        && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
-                        || mTransitionToFullShadeProgress > 0f)) {
-                    mScrimController.legacyTransitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
-                } else {
-                    mScrimController.legacyTransitionTo(ScrimState.AUTH_SCRIMMED);
-                }
+                // Safeguard which prevents the scrim from being stuck in the wrong state
+                mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
             }
             // This will cancel the keyguardFadingAway animation if it is running. We need to do
             // this as otherwise it can remain pending and leave keyguard in a weird state.
@@ -3168,12 +3157,8 @@
                 public void onDozeAmountChanged(float linear, float eased) {
                     if (!lightRevealMigration()
                             && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
-                        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-                            // If wakeAndUnlocking, this is handled in AuthRippleInteractor
-                            if (!mBiometricUnlockController.isWakeAndUnlock()) {
-                                mLightRevealScrim.setRevealAmount(1f - linear);
-                            }
-                        } else {
+                        // If wakeAndUnlocking, this is handled in AuthRippleInteractor
+                        if (!mBiometricUnlockController.isWakeAndUnlock()) {
                             mLightRevealScrim.setRevealAmount(1f - linear);
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 316e1f1..a34ac2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -22,7 +22,7 @@
 import android.hardware.biometrics.BiometricSourceType
 import android.provider.Settings
 import com.android.app.tracing.ListenersTracing.forEachTraced
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
index 4604233..1cca3ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
@@ -57,7 +57,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.kotlin.getOrNull
 import dagger.Lazy
@@ -85,7 +85,7 @@
     private val context: Context,
     @DisplayId private val displayId: Int,
     private val lockScreenUserManager: NotificationLockscreenUserManager,
-    private val statusBarWindowController: StatusBarWindowController,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val wakefulnessLifecycle: WakefulnessLifecycle,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val deviceProvisionedController: DeviceProvisionedController,
@@ -525,7 +525,7 @@
         }
         val rootView = animationController.transitionContainer.rootView
         val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> =
-            statusBarWindowController.wrapAnimationControllerIfInStatusBar(
+            statusBarWindowControllerStore.defaultDisplay.wrapAnimationControllerIfInStatusBar(
                 rootView,
                 animationController
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index d6716a0..e7d9717 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -40,7 +40,7 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
 import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
 import com.android.systemui.util.leak.RotationUtils;
@@ -49,7 +49,7 @@
 
 public class PhoneStatusBarView extends FrameLayout {
     private static final String TAG = "PhoneStatusBarView";
-    private final StatusBarWindowController mStatusBarWindowController;
+    private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
 
     private int mRotationOrientation = -1;
     @Nullable
@@ -75,7 +75,7 @@
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+        mStatusBarWindowControllerStore = Dependency.get(StatusBarWindowControllerStore.class);
     }
 
     void setTouchEventHandler(Gefingerpoken handler) {
@@ -326,7 +326,7 @@
         if (Flags.statusBarStopUpdatingWindowHeight()) {
             return;
         }
-        mStatusBarWindowController.refreshStatusBarHeight();
+        mStatusBarWindowControllerStore.getDefaultDisplay().refreshStatusBarHeight();
     }
 
     interface HasCornerCutoutFetcher {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 069c624..40e5293 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1715,26 +1715,6 @@
         updateScrims();
     }
 
-    public void setHasBackdrop(boolean hasBackdrop) {
-        for (ScrimState state : ScrimState.values()) {
-            state.setHasBackdrop(hasBackdrop);
-        }
-
-        // Backdrop event may arrive after state was already applied,
-        // in this case, back-scrim needs to be re-evaluated
-        if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
-            float newBehindAlpha = mState.getBehindAlpha();
-            if (isNaN(newBehindAlpha)) {
-                throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
-                        + ", back: " + mBehindAlpha);
-            }
-            if (mBehindAlpha != newBehindAlpha) {
-                mBehindAlpha = newBehindAlpha;
-                updateScrims();
-            }
-        }
-    }
-
     private void setKeyguardFadingAway(boolean fadingAway, long duration) {
         for (ScrimState state : ScrimState.values()) {
             state.setKeyguardFadingAway(fadingAway, duration);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index fbba3dc..a0ab612 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -210,7 +210,7 @@
 
         @Override
         public float getMaxLightRevealScrimAlpha() {
-            return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
+            return mWallpaperSupportsAmbientMode ? 0f : 1f;
         }
 
         @Override
@@ -369,7 +369,6 @@
     DockManager mDockManager;
     boolean mDisplayRequiresBlanking;
     boolean mWallpaperSupportsAmbientMode;
-    boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
     boolean mOccludeAnimationPlaying;
     boolean mWakeLockScreenSensorActive;
@@ -489,10 +488,6 @@
         return false;
     }
 
-    public void setHasBackdrop(boolean hasBackdrop) {
-        mHasBackdrop = hasBackdrop;
-    }
-
     public void setWakeLockScreenSensorActive(boolean active) {
         mWakeLockScreenSensorActive = active;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index 8f2d4f9..7145ffe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -28,7 +28,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 
 import javax.inject.Inject;
 
@@ -38,7 +38,7 @@
 @SysUISingleton
 public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener, CoreStartable {
     private final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final StatusBarWindowController mStatusBarWindowController;
+    private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
     private final ShadeViewController mShadeViewController;
     private final PanelExpansionInteractor mPanelExpansionInteractor;
     private final NotificationStackScrollLayoutController mNsslController;
@@ -50,7 +50,7 @@
     @Inject
     StatusBarHeadsUpChangeListener(
             NotificationShadeWindowController notificationShadeWindowController,
-            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowControllerStore statusBarWindowControllerStore,
             ShadeViewController shadeViewController,
             PanelExpansionInteractor panelExpansionInteractor,
             NotificationStackScrollLayoutController nsslController,
@@ -59,7 +59,7 @@
             StatusBarStateController statusBarStateController,
             NotificationRemoteInputManager notificationRemoteInputManager) {
         mNotificationShadeWindowController = notificationShadeWindowController;
-        mStatusBarWindowController = statusBarWindowController;
+        mStatusBarWindowControllerStore = statusBarWindowControllerStore;
         mShadeViewController = shadeViewController;
         mPanelExpansionInteractor = panelExpansionInteractor;
         mNsslController = nsslController;
@@ -78,7 +78,7 @@
     public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
         if (inPinnedMode) {
             mNotificationShadeWindowController.setHeadsUpShowing(true);
-            mStatusBarWindowController.setForceStatusBarVisible(true);
+            mStatusBarWindowControllerStore.getDefaultDisplay().setForceStatusBarVisible(true);
             if (mPanelExpansionInteractor.isFullyCollapsed()) {
                 mShadeViewController.updateTouchableRegion();
             }
@@ -93,7 +93,9 @@
                 // open artificially.
                 mNotificationShadeWindowController.setHeadsUpShowing(false);
                 if (bypassKeyguard) {
-                    mStatusBarWindowController.setForceStatusBarVisible(false);
+                    mStatusBarWindowControllerStore
+                            .getDefaultDisplay()
+                            .setForceStatusBarVisible(false);
                 }
             } else {
                 // we need to keep the panel open artificially, let's wait until the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 17bd538..74c6e72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -47,7 +47,6 @@
 
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.KeyguardMessageAreaController;
 import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -68,7 +67,6 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -77,9 +75,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.DismissAction;
-import com.android.systemui.keyguard.shared.model.Edge;
 import com.android.systemui.keyguard.shared.model.KeyguardDone;
-import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.navigationbar.TaskbarDelegate;
@@ -165,7 +161,6 @@
     private final DreamOverlayStateController mDreamOverlayStateController;
     @Nullable
     private final FoldAodAnimationController mFoldAodAnimationController;
-    KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
     private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
     private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
@@ -463,11 +458,6 @@
             onPanelExpansionChanged(currentState);
         }
         mNotificationContainer = notificationContainer;
-        if (!DeviceEntryUdfpsRefactor.isEnabled()) {
-            mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create(
-                    centralSurfaces.getKeyguardMessageArea());
-        }
-
         mCentralSurfacesRegistered = true;
 
         registerListeners();
@@ -518,24 +508,11 @@
             mListenForCanShowAlternateBouncer.cancel(null);
         }
         mListenForCanShowAlternateBouncer = null;
-        if (!DeviceEntryUdfpsRefactor.isEnabled()) {
-            mListenForAlternateBouncerTransitionSteps = mJavaAdapter.alwaysCollectFlow(
-                    mKeyguardTransitionInteractor
-                            .transition(Edge.create(KeyguardState.ALTERNATE_BOUNCER)),
-                    this::consumeFromAlternateBouncerTransitionSteps
-            );
-
-            mListenForKeyguardAuthenticatedBiometricsHandled = mJavaAdapter.alwaysCollectFlow(
-                    mPrimaryBouncerInteractor.getKeyguardAuthenticatedBiometricsHandled(),
-                    this::consumeKeyguardAuthenticatedBiometricsHandled
-            );
-        } else {
-            // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
-            mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
-                    mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
-                    this::consumeCanShowAlternateBouncer
-            );
-        }
+        // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
+        mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
+                mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
+                this::consumeCanShowAlternateBouncer
+        );
 
         if (KeyguardWmStateRefactor.isEnabled()) {
             // Show the keyguard views whenever we've told WM that the lockscreen is visible.
@@ -792,21 +769,12 @@
             return;
         }
 
-        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-            if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
-                Log.d(TAG, "showBouncer:alternateBouncer.forceShow()");
-                mAlternateBouncerInteractor.forceShow();
-                updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
-            } else {
-                showPrimaryBouncer(scrimmed);
-            }
-            return;
-        }
-
-        if (!mAlternateBouncerInteractor.show()) {
-            showPrimaryBouncer(scrimmed);
-        } else {
+        if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
+            Log.d(TAG, "showBouncer:alternateBouncer.forceShow()");
+            mAlternateBouncerInteractor.forceShow();
             updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
+        } else {
+            showPrimaryBouncer(scrimmed);
         }
     }
 
@@ -921,13 +889,9 @@
                         mKeyguardGoneCancelAction = null;
                     }
 
-                    if (DeviceEntryUdfpsRefactor.isEnabled()) {
-                        Log.d(TAG, "dismissWithAction:alternateBouncer.forceShow()");
-                        mAlternateBouncerInteractor.forceShow();
-                        updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
-                    } else {
-                        updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
-                    }
+                    Log.d(TAG, "dismissWithAction:alternateBouncer.forceShow()");
+                    mAlternateBouncerInteractor.forceShow();
+                    updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
                     setKeyguardMessage(message, null, null);
                     return;
                 }
@@ -1033,11 +997,6 @@
         }
 
         final boolean isShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState();
-        if (mKeyguardMessageAreaController != null) {
-            DeviceEntryUdfpsRefactor.assertInLegacyMode();
-            mKeyguardMessageAreaController.setIsVisible(isShowingAlternateBouncer);
-            mKeyguardMessageAreaController.setMessage("");
-        }
         if (!SceneContainerFlag.isEnabled()) {
             mKeyguardUpdateManager.setAlternateBouncerShowing(isShowingAlternateBouncer);
         }
@@ -1646,12 +1605,7 @@
     /** Display security message to relevant KeyguardMessageArea. */
     public void setKeyguardMessage(String message, ColorStateList colorState,
             BiometricSourceType biometricSourceType) {
-        if (mAlternateBouncerInteractor.isVisibleState()) {
-            if (mKeyguardMessageAreaController != null) {
-                DeviceEntryUdfpsRefactor.assertInLegacyMode();
-                mKeyguardMessageAreaController.setMessage(message, biometricSourceType);
-            }
-        } else {
+        if (!mAlternateBouncerInteractor.isVisibleState()) {
             mPrimaryBouncerInteractor.showMessage(message, colorState);
         }
     }
@@ -1778,66 +1732,6 @@
         }
     }
 
-    /**
-     * An opportunity for the AlternateBouncer to handle the touch instead of sending
-     * the touch to NPVC child views.
-     * @return true if the alternate bouncer should consime the touch and prevent it from
-     * going to its child views
-     */
-    public boolean dispatchTouchEvent(MotionEvent event) {
-        if (shouldInterceptTouchEvent(event)
-                && !mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(event)) {
-            onTouch(event);
-        }
-        return shouldInterceptTouchEvent(event);
-    }
-
-    /**
-     * Whether the touch should be intercepted by the AlternateBouncer before going to the
-     * notification shade's child views.
-     */
-    public boolean shouldInterceptTouchEvent(MotionEvent event) {
-        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-            return false;
-        }
-        return mAlternateBouncerInteractor.isVisibleState();
-    }
-
-    /**
-     * For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently
-     * showing.
-     */
-    public boolean onTouch(MotionEvent event) {
-        if (DeviceEntryUdfpsRefactor.isEnabled()) {
-            return false;
-        }
-
-        boolean handleTouch = shouldInterceptTouchEvent(event);
-        if (handleTouch) {
-            final boolean actionDown = event.getActionMasked() == MotionEvent.ACTION_DOWN;
-            final boolean actionDownThenUp = mAlternateBouncerInteractor.getReceivedDownTouch()
-                    && event.getActionMasked() == MotionEvent.ACTION_UP;
-            final boolean udfpsOverlayWillForwardEventsOutsideNotificationShade =
-                    mKeyguardUpdateManager.isUdfpsEnrolled();
-            final boolean actionOutsideShouldDismissAlternateBouncer =
-                    event.getActionMasked() == MotionEvent.ACTION_OUTSIDE
-                    && !udfpsOverlayWillForwardEventsOutsideNotificationShade;
-            if (actionDown) {
-                mAlternateBouncerInteractor.setReceivedDownTouch(true);
-            } else if ((actionDownThenUp || actionOutsideShouldDismissAlternateBouncer)
-                    && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) {
-                showPrimaryBouncer(true);
-            }
-        }
-
-        // Forward NPVC touches to callbacks in case they want to respond to touches
-        for (KeyguardViewManagerCallback callback: mCallbacks) {
-            callback.onTouch(event);
-        }
-
-        return handleTouch;
-    }
-
     /** Update keyguard position based on a tapped X coordinate. */
     public void updateKeyguardPosition(float x) {
         mPrimaryBouncerInteractor.setKeyguardPosition(x);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 5b03198..5f864e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -15,12 +15,18 @@
  */
 package com.android.systemui.statusbar.phone.dagger
 
+import android.view.Display
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Default
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.core.CommandQueueInitializer
+import com.android.systemui.statusbar.core.MultiDisplayStatusBarInitializerStore
+import com.android.systemui.statusbar.core.SingleDisplayStatusBarInitializerStore
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.core.StatusBarInitializer
 import com.android.systemui.statusbar.core.StatusBarInitializerImpl
+import com.android.systemui.statusbar.core.StatusBarInitializerStore
 import com.android.systemui.statusbar.core.StatusBarOrchestrator
 import com.android.systemui.statusbar.core.StatusBarSimpleFragment
 import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks
@@ -47,15 +53,31 @@
         impl: CentralSurfacesCommandQueueCallbacks
     ): CommandQueue.Callbacks
 
+    @Binds
+    fun initializerFactory(
+        implFactory: StatusBarInitializerImpl.Factory
+    ): StatusBarInitializer.Factory
+
     /** Binds {@link StatusBarInitializer} as a {@link CoreStartable}. */
     @Binds
     @IntoMap
     @ClassKey(StatusBarInitializerImpl::class)
-    fun bindStatusBarInitializer(impl: StatusBarInitializerImpl): CoreStartable
+    fun bindStatusBarInitializer(@Default impl: StatusBarInitializerImpl): CoreStartable
 
-    @Binds fun statusBarInitializer(impl: StatusBarInitializerImpl): StatusBarInitializer
+    @Binds fun statusBarInitializer(@Default impl: StatusBarInitializerImpl): StatusBarInitializer
 
     companion object {
+        // Dagger doesn't support providing AssistedInject types, without a qualifier. Using the
+        // Default qualifier for this reason.
+        @Default
+        @Provides
+        @SysUISingleton
+        fun statusBarInitializerImpl(
+            implFactory: StatusBarInitializerImpl.Factory
+        ): StatusBarInitializerImpl {
+            return implFactory.create(displayId = Display.DEFAULT_DISPLAY)
+        }
+
         @Provides
         @SysUISingleton
         @IntoMap
@@ -83,5 +105,32 @@
                 CoreStartable.NOP
             }
         }
+
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(StatusBarInitializerStore::class)
+        fun initializerStoreAsCoreStartable(
+            multiDisplayStoreLazy: Lazy<MultiDisplayStatusBarInitializerStore>
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayStoreLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
+
+        @Provides
+        @SysUISingleton
+        fun initializerStore(
+            singleDisplayStoreLazy: Lazy<SingleDisplayStatusBarInitializerStore>,
+            multiDisplayStoreLazy: Lazy<MultiDisplayStatusBarInitializerStore>,
+        ): StatusBarInitializerStore {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayStoreLazy.get()
+            } else {
+                singleDisplayStoreLazy.get()
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index c258095..35e30b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -55,7 +55,7 @@
 import com.android.systemui.statusbar.OperatorNameView;
 import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.core.StatusBarSimpleFragment;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
@@ -642,7 +642,7 @@
         }
         boolean showSecondaryOngoingActivityChip =
                 Flags.statusBarScreenSharingChips()
-                        && StatusBarRonChips.isEnabled()
+                        && StatusBarNotifChips.isEnabled()
                         && mHasSecondaryOngoingActivity;
 
         return new StatusBarVisibilityModel(
@@ -684,7 +684,7 @@
 
         boolean showSecondaryOngoingActivityChip =
                 // Secondary chips are only supported when RONs are enabled.
-                StatusBarRonChips.isEnabled()
+                StatusBarNotifChips.isEnabled()
                         && visibilityModel.getShowSecondaryOngoingActivityChip()
                         && !disableNotifications;
         if (showSecondaryOngoingActivityChip) {
@@ -811,7 +811,7 @@
     }
 
     private void showSecondaryOngoingActivityChip(boolean animate) {
-        StatusBarRonChips.assertInNewMode();
+        StatusBarNotifChips.assertInNewMode();
         StatusBarSimpleFragment.assertInLegacyMode();
         animateShow(mSecondaryOngoingActivityChip, animate);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index f026b99..cf877a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 
 import dagger.Module;
 import dagger.Provides;
@@ -125,9 +126,9 @@
     @StatusBarFragmentScope
     static PhoneStatusBarTransitions providePhoneStatusBarTransitions(
             @RootView PhoneStatusBarView view,
-            StatusBarWindowController statusBarWindowController
-    ) {
-        return new PhoneStatusBarTransitions(view, statusBarWindowController.getBackgroundView());
+            StatusBarWindowControllerStore statusBarWindowControllerStore) {
+        return new PhoneStatusBarTransitions(
+                view, statusBarWindowControllerStore.getDefaultDisplay().getBackgroundView());
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index bd6a1c0..3cf8c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -52,7 +52,7 @@
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import com.android.systemui.statusbar.policy.CallbackController
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
 import java.util.concurrent.Executor
@@ -75,7 +75,7 @@
     @Main private val mainExecutor: Executor,
     private val iActivityManager: IActivityManager,
     private val dumpManager: DumpManager,
-    private val statusBarWindowController: StatusBarWindowController,
+    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val swipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler,
     private val statusBarModeRepository: StatusBarModeRepositoryStore,
     @OngoingCallLog private val logger: LogBuffer,
@@ -205,7 +205,9 @@
         this.chipView = chipView
         val backgroundView: ChipBackgroundContainer? =
             chipView.findViewById(R.id.ongoing_activity_chip_background)
-        backgroundView?.maxHeightFetcher = { statusBarWindowController.statusBarHeight }
+        backgroundView?.maxHeightFetcher = {
+            statusBarWindowControllerStore.defaultDisplay.statusBarHeight
+        }
         if (hasOngoingCall()) {
             updateChip()
         }
@@ -339,7 +341,8 @@
             // But, this class still needs to do the non-display logic regardless of the flag.
             uidObserver.registerWithUid(currentCallNotificationInfo.uid)
             if (!currentCallNotificationInfo.statusBarSwipedAway) {
-                statusBarWindowController.setOngoingProcessRequiresStatusBarVisible(true)
+                statusBarWindowControllerStore.defaultDisplay
+                    .setOngoingProcessRequiresStatusBarVisible(true)
             }
             updateGestureListening()
             sendStateChangeEvent()
@@ -405,7 +408,9 @@
         if (!Flags.statusBarScreenSharingChips()) {
             tearDownChipView()
         }
-        statusBarWindowController.setOngoingProcessRequiresStatusBarVisible(false)
+        statusBarWindowControllerStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible(
+            false
+        )
         swipeStatusBarAwayGestureHandler.removeOnGestureDetectedCallback(TAG)
         sendStateChangeEvent()
         uidObserver.unregister()
@@ -429,7 +434,9 @@
     private fun onSwipeAwayGestureDetected() {
         logger.log(TAG, LogLevel.DEBUG, {}, { "Swipe away gesture detected" })
         callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true)
-        statusBarWindowController.setOngoingProcessRequiresStatusBarVisible(false)
+        statusBarWindowControllerStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible(
+            false
+        )
         swipeStatusBarAwayGestureHandler.removeOnGestureDetectedCallback(TAG)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index bad6f80..694a5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.flags.FeatureFlagsClassic
@@ -29,8 +29,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
 import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
@@ -116,7 +116,7 @@
 
     private fun createViewModel(subId: Int): Pair<MobileIconViewModel, CoroutineScope> {
         // Create a child scope so we can cancel it
-        val vmScope = scope.createChildScope(createCoroutineTracingContext("MobileIconViewModel"))
+        val vmScope = scope.createChildScope(newTracingContext("MobileIconViewModel"))
         val vm =
             MobileIconViewModel(
                 subId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index 9c168be..3a07d9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipBinder
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.core.StatusBarSimpleFragment
@@ -83,7 +84,7 @@
                     }
                 }
 
-                if (Flags.statusBarScreenSharingChips() && !Flags.statusBarRonChips()) {
+                if (Flags.statusBarScreenSharingChips() && !StatusBarNotifChips.isEnabled) {
                     val primaryChipView: View =
                         view.requireViewById(R.id.ongoing_activity_chip_primary)
                     launch {
@@ -119,7 +120,7 @@
                     }
                 }
 
-                if (Flags.statusBarScreenSharingChips() && Flags.statusBarRonChips()) {
+                if (Flags.statusBarScreenSharingChips() && StatusBarNotifChips.isEnabled) {
                     val primaryChipView: View =
                         view.requireViewById(R.id.ongoing_activity_chip_primary)
                     val secondaryChipView: View =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index 5f30b37..7d0dadc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.window
 
+import android.content.Context
 import android.view.Display
 import android.view.WindowManager
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
@@ -105,12 +106,19 @@
 @SysUISingleton
 class SingleDisplayStatusBarWindowControllerStore
 @Inject
-constructor(private val controller: StatusBarWindowController) : StatusBarWindowControllerStore {
+constructor(
+    context: Context,
+    viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
+    factory: StatusBarWindowControllerImpl.Factory,
+) : StatusBarWindowControllerStore {
 
     init {
         StatusBarConnectedDisplays.assertInLegacyMode()
     }
 
+    private val controller: StatusBarWindowController =
+        factory.create(context, viewCaptureAwareWindowManager)
+
     override val defaultDisplay = controller
 
     override fun forDisplay(displayId: Int) = controller
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 2135817..d0817d7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -61,7 +61,6 @@
 
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setTheme(androidx.appcompat.R.style.Theme_AppCompat_DayNight);
 
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
         requestWindowFeature(Window.FEATURE_NO_TITLE);
diff --git a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
index de92318..d87607d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
@@ -11,6 +11,7 @@
 import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
 import android.util.Log
 import androidx.annotation.Px
 import com.android.app.tracing.traceSection
@@ -22,36 +23,35 @@
         const val TAG = "SysUiDrawableSize"
 
         /**
-         * Downscales passed Drawable to set maximum width and height. This will only
-         * be done for Drawables that can be downscaled non-destructively - e.g. animated
-         * and stateful drawables will no be downscaled.
+         * Downscales passed Drawable to set maximum width and height. This will only be done for
+         * Drawables that can be downscaled non-destructively - e.g. animated drawables, stateful
+         * drawables, and drawables with mixed-type layers will not be downscaled.
          *
-         * Downscaling will keep the aspect ratio.
-         * This method will not touch drawables that already fit into size specification.
+         * Downscaling will keep the aspect ratio. This method will not touch drawables that already
+         * fit into size specification.
          *
          * @param resources Resources on which to base the density of resized drawable.
          * @param drawable Drawable to downscale.
          * @param maxWidth Maximum width of the downscaled drawable.
          * @param maxHeight Maximum height of the downscaled drawable.
-         *
          * @return returns downscaled drawable if it's possible to downscale it or original if it's
-         *         not.
+         *   not.
          */
         @JvmStatic
         fun downscaleToSize(
             res: Resources,
             drawable: Drawable,
             @Px maxWidth: Int,
-            @Px maxHeight: Int
+            @Px maxHeight: Int,
         ): Drawable {
             traceSection("DrawableSize#downscaleToSize") {
                 // Bitmap drawables can contain big bitmaps as their content while sneaking it past
                 // us using density scaling. Inspect inside the Bitmap drawables for actual bitmap
                 // size for those.
-                val originalWidth = (drawable as? BitmapDrawable)?.bitmap?.width
-                                    ?: drawable.intrinsicWidth
-                val originalHeight = (drawable as? BitmapDrawable)?.bitmap?.height
-                                    ?: drawable.intrinsicHeight
+                val originalWidth =
+                    (drawable as? BitmapDrawable)?.bitmap?.width ?: drawable.intrinsicWidth
+                val originalHeight =
+                    (drawable as? BitmapDrawable)?.bitmap?.height ?: drawable.intrinsicHeight
 
                 // Don't touch drawable if we can't resolve sizes for whatever reason.
                 if (originalWidth <= 0 || originalHeight <= 0) {
@@ -61,14 +61,18 @@
                 // Do not touch drawables that are already within bounds.
                 if (originalWidth < maxWidth && originalHeight < maxHeight) {
                     if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Not resizing $originalWidth x $originalHeight" + " " +
-                                "to $maxWidth x $maxHeight")
+                        Log.d(
+                            TAG,
+                            "Not resizing $originalWidth x $originalHeight" +
+                                " " +
+                                "to $maxWidth x $maxHeight",
+                        )
                     }
 
                     return drawable
                 }
 
-                if (!isSimpleBitmap(drawable)) {
+                if (isComplicatedBitmap(drawable)) {
                     return drawable
                 }
 
@@ -80,19 +84,25 @@
                 val height = (originalHeight * scale).toInt()
 
                 if (width <= 0 || height <= 0) {
-                    Log.w(TAG, "Attempted to resize ${drawable.javaClass.simpleName} " +
-                            "from $originalWidth x $originalHeight to invalid $width x $height.")
+                    Log.w(
+                        TAG,
+                        "Attempted to resize ${drawable.javaClass.simpleName} " +
+                            "from $originalWidth x $originalHeight to invalid $width x $height.",
+                    )
                     return drawable
                 }
 
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Resizing large drawable (${drawable.javaClass.simpleName}) " +
-                            "from $originalWidth x $originalHeight to $width x $height")
+                    Log.d(
+                        TAG,
+                        "Resizing large drawable (${drawable.javaClass.simpleName}) " +
+                            "from $originalWidth x $originalHeight to $width x $height",
+                    )
                 }
 
                 // We want to keep existing config if it's more efficient than 32-bit RGB.
-                val config = (drawable as? BitmapDrawable)?.bitmap?.config
-                        ?: Bitmap.Config.ARGB_8888
+                val config =
+                    (drawable as? BitmapDrawable)?.bitmap?.config ?: Bitmap.Config.ARGB_8888
                 val scaledDrawableBitmap = Bitmap.createBitmap(width, height, config)
                 val canvas = Canvas(scaledDrawableBitmap)
 
@@ -105,8 +115,8 @@
             }
         }
 
-        private fun isSimpleBitmap(drawable: Drawable): Boolean {
-            return !(drawable.isStateful || isAnimated(drawable))
+        private fun isComplicatedBitmap(drawable: Drawable): Boolean {
+            return drawable.isStateful || isAnimated(drawable) || hasComplicatedLayers(drawable)
         }
 
         private fun isAnimated(drawable: Drawable): Boolean {
@@ -119,5 +129,30 @@
                 drawable is AnimatedStateListDrawable ||
                 drawable is AnimatedVectorDrawable
         }
+
+        private fun hasComplicatedLayers(drawable: Drawable): Boolean {
+            if (drawable !is LayerDrawable) {
+                return false
+            }
+            if (drawable.numberOfLayers == 1) {
+                return false
+            }
+
+            val firstLayerType = drawable.getDrawable(0).javaClass
+            for (i in 1..<drawable.numberOfLayers) {
+                val layer = drawable.getDrawable(i)
+                if (layer.javaClass != firstLayerType) {
+                    // If different layers have different drawable types, we shouldn't scale it down
+                    // because we may lose the level information if one of the layers is a bitmap
+                    // and another layer is a level-list. See b/244282477.
+                    return true
+                }
+                if (isComplicatedBitmap(layer)) {
+                    return true
+                }
+            }
+
+            return false
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
index 2af84c7..579af73 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
@@ -16,10 +16,9 @@
 
 package com.android.systemui.util.kotlin
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dagger.qualifiers.Tracing
 import dagger.Module
 import dagger.Provides
 import javax.inject.Singleton
@@ -27,7 +26,6 @@
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 /** Providers for various application-wide coroutines-related constructs. */
 @Module
@@ -35,16 +33,15 @@
     @Provides
     @Singleton
     @Application
-    fun applicationScope(
-        @Main dispatcherContext: CoroutineContext,
-    ): CoroutineScope = CoroutineScope(dispatcherContext + createCoroutineTracingContext("ApplicationScope"))
+    fun applicationScope(@Main dispatcherContext: CoroutineContext): CoroutineScope =
+        CoroutineScope(dispatcherContext + newTracingContext("ApplicationScope"))
 
     @Provides
     @Singleton
     @Main
     @Deprecated(
         "Use @Main CoroutineContext instead",
-        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
     )
     fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
index 4d9aaa6..ea8709f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.util.settings
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.annotation.UserIdInt
 import android.content.ContentResolver
 import android.database.ContentObserver
@@ -24,6 +23,7 @@
 import androidx.annotation.AnyThread
 import androidx.annotation.WorkerThread
 import com.android.app.tracing.TraceUtils.trace
+import com.android.systemui.coroutines.newTracingContext
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -94,7 +94,7 @@
      */
     @AnyThread
     fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-A")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-A")).launch {
             registerContentObserverSync(getUriFor(name), settingsObserver)
         }
 
@@ -109,9 +109,9 @@
     fun registerContentObserverAsync(
         name: String,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-B")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-B")).launch {
             registerContentObserverSync(getUriFor(name), settingsObserver)
             registered.run()
         }
@@ -144,7 +144,7 @@
      */
     @AnyThread
     fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-C")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-C")).launch {
             registerContentObserverSync(uri, settingsObserver)
         }
 
@@ -159,9 +159,9 @@
     fun registerContentObserverAsync(
         uri: Uri,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-D")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-D")).launch {
             registerContentObserverSync(uri, settingsObserver)
             registered.run()
         }
@@ -175,7 +175,7 @@
     fun registerContentObserverSync(
         name: String,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) = registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
 
     /**
@@ -204,9 +204,9 @@
     fun registerContentObserverAsync(
         name: String,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-E")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-E")).launch {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
         }
 
@@ -222,9 +222,9 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-F")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-F")).launch {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
             registered.run()
         }
@@ -273,9 +273,9 @@
     fun registerContentObserverAsync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-G")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-G")).launch {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
         }
 
@@ -291,9 +291,9 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-H")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-H")).launch {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
             registered.run()
         }
@@ -330,7 +330,9 @@
      */
     @AnyThread
     fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-I")).launch { unregisterContentObserver(settingsObserver) }
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-I")).launch {
+            unregisterContentObserver(settingsObserver)
+        }
 
     /**
      * Look up a name in the database.
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
index c820c07..c5deca2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.util.settings
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.annotation.UserIdInt
 import android.annotation.WorkerThread
 import android.content.ContentResolver
@@ -24,6 +23,7 @@
 import android.os.UserHandle
 import android.provider.Settings.SettingNotFoundException
 import com.android.app.tracing.TraceUtils.trace
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
@@ -79,7 +79,7 @@
     }
 
     override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-A")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-A")).launch {
             registerContentObserverForUserSync(uri, settingsObserver, userId)
         }
 
@@ -88,7 +88,7 @@
     override fun registerContentObserverSync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) {
         registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
     }
@@ -111,9 +111,9 @@
     override fun registerContentObserverAsync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-B")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-B")).launch {
             registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
         }
 
@@ -156,9 +156,9 @@
     fun registerContentObserverForUserAsync(
         name: String,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-C")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-C")).launch {
             registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
         }
 
@@ -197,9 +197,9 @@
     fun registerContentObserverForUserAsync(
         uri: Uri,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-D")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-D")).launch {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
         }
 
@@ -214,9 +214,9 @@
         uri: Uri,
         settingsObserver: ContentObserver,
         userHandle: Int,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-E")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-E")).launch {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
             registered.run()
         }
@@ -273,14 +273,14 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-F")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-F")).launch {
             registerContentObserverForUserSync(
                 getUriFor(name),
                 notifyForDescendants,
                 settingsObserver,
-                userHandle
+                userHandle,
             )
         }
     }
@@ -337,14 +337,14 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-G")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-G")).launch {
             registerContentObserverForUserSync(
                 uri,
                 notifyForDescendants,
                 settingsObserver,
-                userHandle
+                userHandle,
             )
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
index 2dd0bda..5e0af63 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.volume.dialog.settings.domain
 
 import android.app.ActivityManager
-import com.android.app.tracing.coroutines.flow.map
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.volume.Events
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
@@ -30,6 +30,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
 @VolumeDialogScope
@@ -49,6 +50,7 @@
                 deviceProvisionedController.isCurrentUserSetup() &&
                     model.lockTaskModeState == ActivityManager.LOCK_TASK_MODE_NONE
             }
+            .flowName("VDSBI#isVisible")
             .stateIn(coroutineScope, SharingStarted.Eagerly, false)
 
     fun onButtonClicked() {
diff --git a/packages/SystemUI/tests/res/drawable/layer_drawable_all_same_type.xml b/packages/SystemUI/tests/res/drawable/layer_drawable_all_same_type.xml
new file mode 100644
index 0000000..d9ea0b9
--- /dev/null
+++ b/packages/SystemUI/tests/res/drawable/layer_drawable_all_same_type.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@drawable/ic_brightness"/>
+    <item android:drawable="@drawable/ic_brightness"/>
+</layer-list>
diff --git a/packages/SystemUI/tests/res/drawable/layer_drawable_different_types.xml b/packages/SystemUI/tests/res/drawable/layer_drawable_different_types.xml
new file mode 100644
index 0000000..796de8f
--- /dev/null
+++ b/packages/SystemUI/tests/res/drawable/layer_drawable_different_types.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <!-- dessert_flan is a PNG while ic_brightness is a level-list. -->
+    <item android:drawable="@drawable/dessert_flan"/>
+    <item android:drawable="@drawable/ic_brightness"/>
+</layer-list>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index e2a6a55..4baca71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -16,21 +16,14 @@
 
 package com.android.systemui.biometrics
 
-import android.graphics.Rect
 import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
 import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
 import android.hardware.biometrics.BiometricRequestConstants.RequestReason
 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
 import android.testing.TestableLooper.RunWithLooper
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.Surface
-import android.view.Surface.Rotation
 import android.view.View
-import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -38,7 +31,6 @@
 import com.android.app.viewcapture.ViewCapture
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
@@ -61,9 +53,7 @@
 import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakefulnessState
-import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.phone.SystemUIDialogManager
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
@@ -86,7 +76,6 @@
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Captor
 import org.mockito.Mock
-import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
@@ -118,7 +107,6 @@
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var dialogManager: SystemUIDialogManager
     @Mock private lateinit var dumpManager: DumpManager
-    @Mock private lateinit var transitionController: LockscreenShadeTransitionController
     @Mock private lateinit var configurationController: ConfigurationController
     @Mock private lateinit var keyguardStateController: KeyguardStateController
     @Mock
@@ -126,8 +114,6 @@
     @Mock private lateinit var udfpsDisplayMode: UdfpsDisplayModeProvider
     @Mock private lateinit var controllerCallback: IUdfpsOverlayControllerCallback
     @Mock private lateinit var udfpsController: UdfpsController
-    @Mock private lateinit var udfpsView: UdfpsView
-    @Mock private lateinit var mUdfpsKeyguardViewLegacy: UdfpsKeyguardViewLegacy
     @Mock private lateinit var mActivityTransitionAnimator: ActivityTransitionAnimator
     @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
     @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@@ -147,7 +133,7 @@
     private lateinit var powerInteractor: PowerInteractor
     private lateinit var testScope: TestScope
 
-    private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
+    private val onTouch = { _: View, _: MotionEvent -> true }
     private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams()
     private lateinit var controllerOverlay: UdfpsControllerOverlay
 
@@ -158,53 +144,37 @@
         powerInteractor = kosmos.powerInteractor
         keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
         keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
-        whenever(inflater.inflate(R.layout.udfps_view, null, false)).thenReturn(udfpsView)
-        whenever(inflater.inflate(R.layout.udfps_bp_view, null))
-            .thenReturn(mock(UdfpsBpView::class.java))
-        whenever(inflater.inflate(R.layout.udfps_keyguard_view_legacy, null))
-            .thenReturn(mUdfpsKeyguardViewLegacy)
-        whenever(inflater.inflate(R.layout.udfps_fpm_empty_view, null))
-            .thenReturn(mock(UdfpsFpmEmptyView::class.java))
     }
 
     private suspend fun withReasonSuspend(
         @RequestReason reason: Int,
         isDebuggable: Boolean = false,
-        enableDeviceEntryUdfpsRefactor: Boolean = false,
         block: suspend () -> Unit,
     ) {
-        withReason(
-            reason,
-            isDebuggable,
-            enableDeviceEntryUdfpsRefactor,
-        )
+        withReason(reason, isDebuggable)
         block()
     }
 
     private fun withReason(
         @RequestReason reason: Int,
         isDebuggable: Boolean = false,
-        enableDeviceEntryUdfpsRefactor: Boolean = false,
         block: () -> Unit = {},
     ) {
-        if (enableDeviceEntryUdfpsRefactor) {
-            mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-        } else {
-            mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-        }
         controllerOverlay =
             UdfpsControllerOverlay(
                 context,
                 inflater,
-                ViewCaptureAwareWindowManager(windowManager, lazyViewCapture,
-                        isViewCaptureEnabled = false),
+                ViewCaptureAwareWindowManager(
+                    windowManager,
+                    lazyViewCapture,
+                    isViewCaptureEnabled = false,
+                ),
                 accessibilityManager,
                 statusBarStateController,
                 statusBarKeyguardViewManager,
                 keyguardUpdateMonitor,
                 dialogManager,
                 dumpManager,
-                transitionController,
                 configurationController,
                 keyguardStateController,
                 unlockedScreenOffAnimationController,
@@ -230,117 +200,6 @@
         block()
     }
 
-    @Test fun showUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { showUdfpsOverlay() }
-
-    @Test
-    fun showUdfpsOverlay_keyguard() =
-        withReason(REASON_AUTH_KEYGUARD) {
-            showUdfpsOverlay()
-            verify(mUdfpsKeyguardViewLegacy).updateSensorLocation(eq(overlayParams.sensorBounds))
-        }
-
-    @Test fun showUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { showUdfpsOverlay() }
-
-    private fun withRotation(@Rotation rotation: Int, block: () -> Unit) {
-        // Sensor that's in the top left corner of the display in natural orientation.
-        val sensorBounds = Rect(0, 0, SENSOR_WIDTH, SENSOR_HEIGHT)
-        val overlayBounds = Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)
-        overlayParams =
-            UdfpsOverlayParams(
-                sensorBounds,
-                overlayBounds,
-                DISPLAY_WIDTH,
-                DISPLAY_HEIGHT,
-                scaleFactor = 1f,
-                rotation
-            )
-        block()
-    }
-
-    @Test
-    fun showUdfpsOverlay_withRotation0() =
-        withRotation(Surface.ROTATION_0) {
-            withReason(REASON_AUTH_BP) {
-                controllerOverlay.show(udfpsController, overlayParams)
-                verify(windowManager)
-                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
-
-                // ROTATION_0 is the native orientation. Sensor should stay in the top left corner.
-                val lp = layoutParamsCaptor.value
-                assertThat(lp.x).isEqualTo(0)
-                assertThat(lp.y).isEqualTo(0)
-                assertThat(lp.width).isEqualTo(DISPLAY_WIDTH)
-                assertThat(lp.height).isEqualTo(DISPLAY_HEIGHT)
-            }
-        }
-
-    @Test
-    fun showUdfpsOverlay_withRotation180() =
-        withRotation(Surface.ROTATION_180) {
-            withReason(REASON_AUTH_BP) {
-                controllerOverlay.show(udfpsController, overlayParams)
-                verify(windowManager)
-                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
-
-                // ROTATION_180 is not supported. Sensor should stay in the top left corner.
-                val lp = layoutParamsCaptor.value
-                assertThat(lp.x).isEqualTo(0)
-                assertThat(lp.y).isEqualTo(0)
-                assertThat(lp.width).isEqualTo(DISPLAY_WIDTH)
-                assertThat(lp.height).isEqualTo(DISPLAY_HEIGHT)
-            }
-        }
-
-    @Test
-    fun showUdfpsOverlay_withRotation90() =
-        withRotation(Surface.ROTATION_90) {
-            withReason(REASON_AUTH_BP) {
-                controllerOverlay.show(udfpsController, overlayParams)
-                verify(windowManager)
-                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
-
-                // Sensor should be in the bottom left corner in ROTATION_90.
-                val lp = layoutParamsCaptor.value
-                assertThat(lp.x).isEqualTo(0)
-                assertThat(lp.y).isEqualTo(0)
-                assertThat(lp.width).isEqualTo(DISPLAY_HEIGHT)
-                assertThat(lp.height).isEqualTo(DISPLAY_WIDTH)
-            }
-        }
-
-    @Test
-    fun showUdfpsOverlay_withRotation270() =
-        withRotation(Surface.ROTATION_270) {
-            withReason(REASON_AUTH_BP) {
-                controllerOverlay.show(udfpsController, overlayParams)
-                verify(windowManager)
-                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
-
-                // Sensor should be in the top right corner in ROTATION_270.
-                val lp = layoutParamsCaptor.value
-                assertThat(lp.x).isEqualTo(0)
-                assertThat(lp.y).isEqualTo(0)
-                assertThat(lp.width).isEqualTo(DISPLAY_HEIGHT)
-                assertThat(lp.height).isEqualTo(DISPLAY_WIDTH)
-            }
-        }
-
-    @Test
-    fun showUdfpsOverlay_awake() =
-        testScope.runTest {
-            withReason(REASON_AUTH_KEYGUARD) {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.AWAKE,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
-                )
-                runCurrent()
-                controllerOverlay.show(udfpsController, overlayParams)
-                runCurrent()
-                verify(windowManager).addView(any(), any())
-            }
-        }
-
     @Test
     fun showUdfpsOverlay_whileGoingToSleep() =
         testScope.runTest {
@@ -412,91 +271,9 @@
         }
 
     @Test
-    fun showUdfpsOverlay_afterFinishedTransitioningToAOD() =
-        testScope.runTest {
-            withReasonSuspend(REASON_AUTH_KEYGUARD) {
-                keyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.OFF,
-                    to = KeyguardState.GONE,
-                    testScope = this,
-                )
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.STARTING_TO_SLEEP,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
-                )
-                runCurrent()
-
-                // WHEN a request comes to show the view
-                controllerOverlay.show(udfpsController, overlayParams)
-                runCurrent()
-
-                // THEN the view does not get added immediately
-                verify(windowManager, never()).addView(any(), any())
-
-                // WHEN the device finishes transitioning to AOD
-                keyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.GONE,
-                    to = KeyguardState.AOD,
-                    testScope = this,
-                )
-                runCurrent()
-
-                // THEN the view gets added
-                verify(windowManager)
-                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
-            }
-        }
-
-    private fun showUdfpsOverlay() {
-        val didShow = controllerOverlay.show(udfpsController, overlayParams)
-
-        verify(windowManager).addView(eq(controllerOverlay.getTouchOverlay()), any())
-        verify(udfpsView).setUdfpsDisplayModeProvider(eq(udfpsDisplayMode))
-        verify(udfpsView).animationViewController = any()
-        verify(udfpsView).addView(any())
-
-        assertThat(didShow).isTrue()
-        assertThat(controllerOverlay.isShowing).isTrue()
-        assertThat(controllerOverlay.isHiding).isFalse()
-        assertThat(controllerOverlay.getTouchOverlay()).isNotNull()
-    }
-
-    @Test fun hideUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { hideUdfpsOverlay() }
-
-    @Test fun hideUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) { hideUdfpsOverlay() }
-
-    @Test fun hideUdfpsOverlay_settings() = withReason(REASON_AUTH_SETTINGS) { hideUdfpsOverlay() }
-
-    @Test fun hideUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { hideUdfpsOverlay() }
-
-    private fun hideUdfpsOverlay() {
-        val didShow = controllerOverlay.show(udfpsController, overlayParams)
-        val view = controllerOverlay.getTouchOverlay()
-        view?.let { whenever(view.parent).thenReturn(mock(ViewGroup::class.java)) }
-        val didHide = controllerOverlay.hide()
-
-        verify(windowManager).removeView(eq(view))
-
-        assertThat(didShow).isTrue()
-        assertThat(didHide).isTrue()
-        assertThat(controllerOverlay.getTouchOverlay()).isNull()
-        assertThat(controllerOverlay.animationViewController).isNull()
-        assertThat(controllerOverlay.isShowing).isFalse()
-        assertThat(controllerOverlay.isHiding).isTrue()
-    }
-
-    @Test
     fun canNotHide() = withReason(REASON_AUTH_BP) { assertThat(controllerOverlay.hide()).isFalse() }
 
     @Test
-    fun canNotReshow() =
-        withReason(REASON_AUTH_BP) {
-            assertThat(controllerOverlay.show(udfpsController, overlayParams)).isTrue()
-            assertThat(controllerOverlay.show(udfpsController, overlayParams)).isFalse()
-        }
-
-    @Test
     fun cancels() =
         withReason(REASON_AUTH_BP) {
             controllerOverlay.cancel()
@@ -504,16 +281,6 @@
         }
 
     @Test
-    fun unconfigureDisplayOnHide() =
-        withReason(REASON_AUTH_BP) {
-            whenever(udfpsView.isDisplayConfigured).thenReturn(true)
-
-            controllerOverlay.show(udfpsController, overlayParams)
-            controllerOverlay.hide()
-            verify(udfpsView).unconfigureDisplay()
-        }
-
-    @Test
     fun matchesRequestIds() =
         withReason(REASON_AUTH_BP) {
             assertThat(controllerOverlay.matchesRequestId(REQUEST_ID)).isTrue()
@@ -521,29 +288,9 @@
         }
 
     @Test
-    fun smallOverlayOnEnrollmentWithA11y() =
-        withRotation(Surface.ROTATION_0) {
-            withReason(REASON_ENROLL_ENROLLING) {
-                // When a11y enabled during enrollment
-                whenever(accessibilityManager.isTouchExplorationEnabled).thenReturn(true)
-
-                controllerOverlay.show(udfpsController, overlayParams)
-                verify(windowManager)
-                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
-
-                // Layout params should use sensor bounds
-                val lp = layoutParamsCaptor.value
-                assertThat(lp.width).isEqualTo(overlayParams.sensorBounds.width())
-                assertThat(lp.height).isEqualTo(overlayParams.sensorBounds.height())
-            }
-        }
-
-    @Test
     fun addViewPending_layoutIsNotUpdated() =
         testScope.runTest {
             withReasonSuspend(REASON_AUTH_KEYGUARD) {
-                mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-
                 // GIVEN going to sleep
                 keyguardTransitionRepository.sendTransitionSteps(
                     from = KeyguardState.OFF,
@@ -574,26 +321,4 @@
                 controllerOverlay.hide()
             }
         }
-
-    @Test
-    fun updateOverlayParams_viewLayoutUpdated() =
-        testScope.runTest {
-            withReasonSuspend(REASON_AUTH_KEYGUARD) {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.AWAKE,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
-                )
-                runCurrent()
-                controllerOverlay.show(udfpsController, overlayParams)
-                runCurrent()
-                verify(windowManager).addView(any(), any())
-
-                // WHEN updateOverlayParams gets called
-                controllerOverlay.updateOverlayParams(overlayParams)
-
-                // THEN the view layout is updated
-                verify(windowManager).updateViewLayout(any(), any())
-            }
-        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index ae635b8..df50f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -77,6 +77,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 import com.android.systemui.util.RingerModeLiveData;
@@ -125,6 +126,7 @@
     @Mock private LightBarController mLightBarController;
     @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
     @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private StatusBarWindowControllerStore mStatusBarWindowControllerStore;
     @Mock private IWindowManager mWindowManager;
     @Mock private Executor mBackgroundExecutor;
     @Mock private UiEventLogger mUiEventLogger;
@@ -155,7 +157,8 @@
         when(mUserContextProvider.getUserContext()).thenReturn(mContext);
         when(mResources.getConfiguration()).thenReturn(
                 getContext().getResources().getConfiguration());
-
+        when(mStatusBarWindowControllerStore.getDefaultDisplay())
+                .thenReturn(mStatusBarWindowController);
         mGlobalSettings = new FakeGlobalSettings();
         mSecureSettings = new FakeSettings();
         mInteractor = mKosmos.getGlobalActionsInteractor();
@@ -184,7 +187,7 @@
                 mStatusBarService,
                 mLightBarController,
                 mNotificationShadeWindowController,
-                mStatusBarWindowController,
+                mStatusBarWindowControllerStore,
                 mWindowManager,
                 mBackgroundExecutor,
                 mUiEventLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index 96a0aad..ecc62e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -298,7 +298,7 @@
             underTest.applyDefaultConstraints(cs)
             val referencedIds =
                 cs.getReferencedIds(R.id.weather_clock_date_and_icons_barrier_bottom)
-            referencedIds.contentEquals(intArrayOf(R.id.lockscreen_clock_view))
+            referencedIds.contentEquals(intArrayOf(customR.id.lockscreen_clock_view))
         }
 
     @Test
@@ -323,7 +323,7 @@
         }
 
     private fun assertLargeClockTop(cs: ConstraintSet, expectedLargeClockTopMargin: Int) {
-        val largeClockConstraint = cs.getConstraint(R.id.lockscreen_clock_view_large)
+        val largeClockConstraint = cs.getConstraint(customR.id.lockscreen_clock_view_large)
         assertThat(largeClockConstraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
         assertThat(largeClockConstraint.layout.topMargin).isEqualTo(expectedLargeClockTopMargin)
     }
@@ -332,7 +332,7 @@
         val smallClockGuidelineConstraint = cs.getConstraint(R.id.small_clock_guideline_top)
         assertThat(smallClockGuidelineConstraint.layout.topToTop).isEqualTo(-1)
 
-        val smallClockConstraint = cs.getConstraint(R.id.lockscreen_clock_view)
+        val smallClockConstraint = cs.getConstraint(customR.id.lockscreen_clock_view)
         assertThat(smallClockConstraint.layout.topToBottom)
             .isEqualTo(R.id.small_clock_guideline_top)
         assertThat(smallClockConstraint.layout.topMargin).isEqualTo(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index bfb8a57..cea51a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -18,13 +18,11 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.graphics.Point
-import android.platform.test.annotations.DisableFlags
 import android.view.WindowManager
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.keyguard.LegacyLockIconViewController
 import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
@@ -60,7 +58,6 @@
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
     @Mock private lateinit var notificationPanelView: NotificationPanelView
     private lateinit var featureFlags: FakeFeatureFlags
-    @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
     @Mock private lateinit var falsingManager: FalsingManager
     @Mock private lateinit var deviceEntryIconViewModel: DeviceEntryIconViewModel
     private lateinit var underTest: DefaultDeviceEntrySection
@@ -81,7 +78,6 @@
                 context,
                 notificationPanelView,
                 featureFlags,
-                { lockIconViewController },
                 { deviceEntryIconViewModel },
                 { mock(DeviceEntryForegroundViewModel::class.java) },
                 { mock(DeviceEntryBackgroundViewModel::class.java) },
@@ -102,37 +98,13 @@
     @Test
     fun addViewsConditionally_migrateAndRefactorFlagsOn() {
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
-        mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
         val constraintLayout = ConstraintLayout(context, null)
         underTest.addViews(constraintLayout)
         assertThat(constraintLayout.childCount).isGreaterThan(0)
     }
 
     @Test
-    @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
-    fun addViewsConditionally_migrateFlagOff() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-        val constraintLayout = ConstraintLayout(context, null)
-        underTest.addViews(constraintLayout)
-        assertThat(constraintLayout.childCount).isEqualTo(0)
-    }
-
-    @Test
-    fun applyConstraints_udfps_refactor_off() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-        val cs = ConstraintSet()
-        underTest.applyConstraints(cs)
-
-        val constraint = cs.getConstraint(R.id.lock_icon_view)
-
-        assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
-        assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID)
-    }
-
-    @Test
-    fun applyConstraints_udfps_refactor_on() {
-        mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+    fun applyConstraints() {
         whenever(deviceEntryIconViewModel.isUdfpsSupported).thenReturn(MutableStateFlow(false))
         val cs = ConstraintSet()
         underTest.applyConstraints(cs)
@@ -144,24 +116,7 @@
     }
 
     @Test
-    fun testCenterIcon_udfps_refactor_off() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-        val cs = ConstraintSet()
-        underTest.centerIcon(Point(5, 6), 1F, cs)
-
-        val constraint = cs.getConstraint(R.id.lock_icon_view)
-
-        assertThat(constraint.layout.mWidth).isEqualTo(2)
-        assertThat(constraint.layout.mHeight).isEqualTo(2)
-        assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
-        assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID)
-        assertThat(constraint.layout.topMargin).isEqualTo(5)
-        assertThat(constraint.layout.startMargin).isEqualTo(4)
-    }
-
-    @Test
-    fun testCenterIcon_udfps_refactor_on() {
-        mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+    fun testCenterIcon() {
         val cs = ConstraintSet()
         underTest.centerIcon(Point(5, 6), 1F, cs)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt
new file mode 100644
index 0000000..0d1d37a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarInitializerStoreTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 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.core
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.unconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayStatusBarInitializerStoreTest : SysuiTestCase() {
+
+    private val kosmos =
+        testKosmos().also {
+            // Using unconfinedTestDispatcher to avoid having to call `runCurrent` in the tests.
+            it.testDispatcher = it.unconfinedTestDispatcher
+        }
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+    private val store = kosmos.multiDisplayStatusBarInitializerStore
+
+    @Before
+    fun start() {
+        store.start()
+    }
+
+    @Before
+    fun addDisplays() = runBlocking {
+        fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY_ID)
+        fakeDisplayRepository.addDisplay(NON_DEFAULT_DISPLAY_ID)
+    }
+
+    @Test
+    fun forDisplay_defaultDisplay_multipleCalls_returnsSameInstance() =
+        testScope.runTest {
+            val controller = store.defaultDisplay
+
+            assertThat(store.defaultDisplay).isSameInstanceAs(controller)
+        }
+
+    @Test
+    fun forDisplay_nonDefaultDisplay_multipleCalls_returnsSameInstance() =
+        testScope.runTest {
+            val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isSameInstanceAs(controller)
+        }
+
+    @Test
+    fun forDisplay_nonDefaultDisplay_afterDisplayRemoved_returnsNewInstance() =
+        testScope.runTest {
+            val controller = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            fakeDisplayRepository.removeDisplay(NON_DEFAULT_DISPLAY_ID)
+            fakeDisplayRepository.addDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(controller)
+        }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun forDisplay_nonExistingDisplayId_throws() =
+        testScope.runTest { store.forDisplay(NON_EXISTING_DISPLAY_ID) }
+
+    companion object {
+        private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
+        private const val NON_DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1
+        private const val NON_EXISTING_DISPLAY_ID = Display.DEFAULT_DISPLAY + 2
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index 376873d..5d8a8fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.BatteryStatusChip
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
@@ -63,6 +64,7 @@
     @Mock private lateinit var systemEventCoordinator: SystemEventCoordinator
 
     @Mock private lateinit var statusBarWindowController: StatusBarWindowController
+    @Mock private lateinit var statusBarWindowControllerStore: StatusBarWindowControllerStore
 
     @Mock private lateinit var statusBarContentInsetProvider: StatusBarContentInsetsProvider
 
@@ -82,12 +84,14 @@
     fun setup() {
         MockitoAnnotations.initMocks(this)
 
+        whenever(statusBarWindowControllerStore.defaultDisplay)
+            .thenReturn(statusBarWindowController)
         systemClock = FakeSystemClock()
         chipAnimationController =
             SystemEventChipAnimationController(
                 mContext,
-                statusBarWindowController,
-                statusBarContentInsetProvider
+                statusBarWindowControllerStore,
+                statusBarContentInsetProvider,
             )
 
         // StatusBarContentInsetProvider is mocked. Ensure that it returns some mocked values.
@@ -660,7 +664,7 @@
             SystemStatusAnimationSchedulerImpl(
                 systemEventCoordinator,
                 chipAnimationController,
-                statusBarWindowController,
+                statusBarWindowControllerStore,
                 dumpManager,
                 systemClock,
                 CoroutineScope(StandardTestDispatcher(testScope.testScheduler)),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index ed7383c..e3e2491 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -612,6 +612,8 @@
         Assert.assertNull(child.getParent());
         Assert.assertNull(child.getNotificationParent());
         Assert.assertFalse(child.keepInParentForDismissAnimation());
+        verify(mNotificationTestHelper.getMockLogger())
+                .logCancelAppearDrawing(child.getEntry(), false);
         verifyNoMoreInteractions(mNotificationTestHelper.getMockLogger());
     }
 
@@ -1013,7 +1015,7 @@
         assertThat(row.isHeadsUpAnimatingAway()).isTrue();
 
         // on disappear animation ends
-        row.onAppearAnimationFinished(/* wasAppearing = */ false);
+        row.onAppearAnimationFinished(/* wasAppearing = */ false, /* cancelled = */ false);
         assertThat(row.isHeadsUpAnimatingAway()).isFalse();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 15ea811..44d81a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -21,7 +21,6 @@
 import static android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED;
 import static android.provider.Settings.Global.HEADS_UP_ON;
 
-import static com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR;
 import static com.android.systemui.Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_REWRITE;
 import static com.android.systemui.Flags.FLAG_LIGHT_REVEAL_MIGRATION;
 import static com.android.systemui.flags.Flags.SHORTCUT_LIST_SEARCH_LAYOUT;
@@ -170,6 +169,7 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
 import com.android.systemui.statusbar.core.StatusBarOrchestrator;
+import com.android.systemui.statusbar.core.StatusBarSimpleFragment;
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -194,6 +194,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.util.FakeEventLog;
 import com.android.systemui.util.WallpaperController;
@@ -292,6 +293,7 @@
     @Mock private KeyguardBypassController mKeyguardBypassController;
     @Mock private AutoHideController mAutoHideController;
     @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private StatusBarWindowControllerStore mStatusBarWindowControllerStore;
     @Mock private Provider<CollapsedStatusBarFragment> mCollapsedStatusBarFragmentProvider;
     @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private Bubbles mBubbles;
@@ -383,6 +385,9 @@
 
         when(mBubbles.canShowBubbleNotification()).thenReturn(true);
 
+        when(mStatusBarWindowControllerStore.getDefaultDisplay())
+                .thenReturn(mStatusBarWindowController);
+
         mVisualInterruptionDecisionProvider =
                 VisualInterruptionDecisionProviderTestUtil.INSTANCE.createProviderByFlag(
                         mAmbientDisplayConfiguration,
@@ -465,7 +470,7 @@
                     mKeyguardStateController,
                     mStatusBarStateController,
                     mStatusBarKeyguardViewManager,
-                    mStatusBarWindowController,
+                    mStatusBarWindowControllerStore,
                     mDeviceProvisionedController,
                     mNotificationShadeWindowController,
                     0,
@@ -507,10 +512,11 @@
                 mLightBarController,
                 mAutoHideController,
                 new StatusBarInitializerImpl(
-                        mStatusBarWindowController,
+                        mContext.getDisplayId(),
+                        mStatusBarWindowControllerStore,
                         mCollapsedStatusBarFragmentProvider,
                         emptySet()),
-                mStatusBarWindowController,
+                mStatusBarWindowControllerStore,
                 mStatusBarWindowStateController,
                 new FakeStatusBarModeRepository(),
                 mKeyguardUpdateMonitor,
@@ -852,34 +858,6 @@
     }
 
     @Test
-    @DisableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void testSetDozingNotUnlocking_transitionToAuthScrimmed_cancelKeyguardFadingAway() {
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
-
-        mCentralSurfaces.updateScrimController();
-
-        verify(mScrimController).legacyTransitionTo(eq(ScrimState.AUTH_SCRIMMED_SHADE));
-        verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
-    }
-
-    @Test
-    @DisableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void testOccludingQSNotExpanded_flagOff_transitionToAuthScrimmed() {
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // GIVEN device occluded and panel is NOT expanded
-        mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
-        when(mKeyguardStateController.isOccluded()).thenReturn(true);
-        when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(false);
-
-        mCentralSurfaces.updateScrimController();
-
-        verify(mScrimController).legacyTransitionTo(eq(ScrimState.AUTH_SCRIMMED));
-    }
-
-    @Test
-    @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
     public void testNotOccluding_QSNotExpanded_flagOn_doesNotTransitionScrimState() {
         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
 
@@ -895,7 +873,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
     public void testNotOccluding_QSExpanded_flagOn_doesTransitionScrimStateToKeyguard() {
         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
 
@@ -911,21 +888,6 @@
     }
 
     @Test
-    @DisableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
-    public void testOccludingQSExpanded_transitionToAuthScrimmedShade() {
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-
-        // GIVEN device occluded and qs IS expanded
-        mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
-        when(mKeyguardStateController.isOccluded()).thenReturn(true);
-        when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true);
-
-        mCentralSurfaces.updateScrimController();
-
-        verify(mScrimController).legacyTransitionTo(eq(ScrimState.AUTH_SCRIMMED_SHADE));
-    }
-
-    @Test
     public void testEnteringGlanceableHub_updatesScrim() {
         // Transition to the glanceable hub.
         mKosmos.getCommunalRepository()
@@ -1149,6 +1111,7 @@
     }
 
     @Test
+    @DisableFlags(StatusBarSimpleFragment.FLAG_NAME)
     public void bubbleBarVisibility() {
         createCentralSurfaces();
         mCentralSurfaces.onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
index 68df748..ee79ca0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
@@ -57,10 +58,15 @@
         get() = view.requireViewById(R.id.system_icons)
 
     private val windowController = mock<StatusBarWindowController>()
+    private val windowControllerStore = mock<StatusBarWindowControllerStore>()
 
     @Before
     fun setUp() {
-        mDependency.injectTestDependency(StatusBarWindowController::class.java, windowController)
+        whenever(windowControllerStore.defaultDisplay).thenReturn(windowController)
+        mDependency.injectTestDependency(
+            StatusBarWindowControllerStore::class.java,
+            windowControllerStore,
+        )
         context.ensureTestableResources()
         view = spy(createStatusBarView())
         whenever(view.rootWindowInsets).thenReturn(emptyWindowInsets())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index e804b33..eecf36e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -309,8 +309,6 @@
         // Attach behind scrim so flows that are collecting on it start running.
         ViewUtils.attachView(mScrimBehind);
 
-        mScrimController.setHasBackdrop(false);
-
         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
         mTestScope.getTestScheduler().runCurrent();
 
@@ -483,47 +481,6 @@
     }
 
     @Test
-    public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() {
-        mScrimController.setHasBackdrop(true);
-        mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
-        mTestScope.getTestScheduler().runCurrent();
-
-        mScrimController.legacyTransitionTo(ScrimState.AOD);
-        finishAnimationsImmediately();
-
-        assertScrimAlpha(Map.of(
-                mScrimInFront, TRANSPARENT,
-                mScrimBehind, TRANSPARENT));
-        assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
-
-        assertScrimTinted(Map.of(
-                mScrimInFront, true,
-                mScrimBehind, true
-        ));
-    }
-
-    @Test
-    public void setHasBackdrop_withAodWallpaperAndAlbumArt() {
-        mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
-        mTestScope.getTestScheduler().runCurrent();
-
-        mScrimController.legacyTransitionTo(ScrimState.AOD);
-        finishAnimationsImmediately();
-        mScrimController.setHasBackdrop(true);
-        finishAnimationsImmediately();
-
-        assertScrimAlpha(Map.of(
-                mScrimInFront, TRANSPARENT,
-                mScrimBehind, TRANSPARENT));
-        assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
-
-        assertScrimTinted(Map.of(
-                mScrimInFront, true,
-                mScrimBehind, true
-        ));
-    }
-
-    @Test
     public void transitionToAod_withFrontAlphaUpdates() {
         // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
@@ -1356,7 +1313,6 @@
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
-        mScrimController.setHasBackdrop(false);
         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
         mTestScope.getTestScheduler().runCurrent();
         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index e57e8d1..15ef917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -16,7 +16,6 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS;
 import static com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS;
 import static com.android.systemui.Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT;
 import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
@@ -61,6 +60,7 @@
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.OperatorNameViewController;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -633,7 +633,7 @@
     @Test
     @EnableFlags({
             FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
-            FLAG_STATUS_BAR_RON_CHIPS,
+            StatusBarNotifChips.FLAG_NAME,
             FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
     public void hasPrimaryOngoingActivity_viewsUnchangedWhenSimpleFragmentFlagOn() {
         resumeAndGetFragment();
@@ -660,8 +660,8 @@
 
     @Test
     @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
-    public void hasSecondaryOngoingActivity_butRonsFlagOff_secondaryChipHidden() {
+    @DisableFlags({StatusBarNotifChips.FLAG_NAME, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+    public void hasSecondaryOngoingActivity_butNotifsFlagOff_secondaryChipHidden() {
         resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -673,7 +673,7 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
     public void hasSecondaryOngoingActivity_flagOn_secondaryChipShownAndNotificationIconsHidden() {
         resumeAndGetFragment();
@@ -689,8 +689,8 @@
 
     @Test
     @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
-    public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_ronsFlagOff() {
+    @DisableFlags({StatusBarNotifChips.FLAG_NAME, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+    public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -705,9 +705,9 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
-    public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_ronsFlagOn() {
+    public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -724,8 +724,8 @@
 
     @Test
     @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
-    public void hasOngoingActivityButAlsoHun_chipHidden_ronsFlagOff() {
+    @DisableFlags({StatusBarNotifChips.FLAG_NAME, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+    public void hasOngoingActivityButAlsoHun_chipHidden_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -740,9 +740,9 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
-    public void hasOngoingActivitiesButAlsoHun_chipsHidden_ronsFlagOn() {
+    public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -759,8 +759,8 @@
 
     @Test
     @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
-    public void primaryOngoingActivityEnded_chipHidden_ronsFlagOff() {
+    @DisableFlags({StatusBarNotifChips.FLAG_NAME, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+    public void primaryOngoingActivityEnded_chipHidden_notifsFlagOff() {
         resumeAndGetFragment();
 
         // Ongoing activity started
@@ -781,9 +781,9 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
-    public void primaryOngoingActivityEnded_chipHidden_ronsFlagOn() {
+    public void primaryOngoingActivityEnded_chipHidden_notifsFlagOn() {
         resumeAndGetFragment();
 
         // Ongoing activity started
@@ -804,7 +804,7 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
     public void secondaryOngoingActivityEnded_chipHidden() {
         resumeAndGetFragment();
@@ -828,8 +828,8 @@
 
     @Test
     @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
-    public void hasOngoingActivity_hidesNotifsWithoutAnimation_ronsFlagOff() {
+    @DisableFlags({StatusBarNotifChips.FLAG_NAME, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+    public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         // Enable animations for testing so that we can verify we still aren't animating
         fragment.enableAnimationsForTesting();
@@ -846,9 +846,9 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
-    public void hasOngoingActivity_hidesNotifsWithoutAnimation_ronsFlagOn() {
+    public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         // Enable animations for testing so that we can verify we still aren't animating
         fragment.enableAnimationsForTesting();
@@ -866,8 +866,8 @@
 
     @Test
     @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
-    public void screenSharingChipsEnabled_ignoresOngoingCallController_ronsFlagOff() {
+    @DisableFlags({StatusBarNotifChips.FLAG_NAME, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+    public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN there *is* an ongoing call via old callback
@@ -898,9 +898,9 @@
     }
 
     @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
     @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
-    public void screenSharingChipsEnabled_ignoresOngoingCallController_ronsFlagOn() {
+    public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN there *is* an ongoing call via old callback
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 9cfb0bb..1ceb20a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -46,6 +46,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
@@ -197,6 +198,8 @@
 import com.android.wm.shell.taskview.TaskViewTransitions;
 import com.android.wm.shell.transition.Transitions;
 
+import kotlin.Lazy;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -215,7 +218,6 @@
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
-import kotlin.Lazy;
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
 import platform.test.runner.parameterized.Parameters;
 
@@ -2470,6 +2472,52 @@
         verify(stackView, never()).showOverflow(anyBoolean());
     }
 
+    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+    @Test
+    public void testEventLogging_bubbleBar_addBubble() {
+        mBubbleProperties.mIsBubbleBarEnabled = true;
+        mPositioner.setIsLargeScreen(true);
+        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+        mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+        mEntryListener.onEntryAdded(mRow);
+
+        verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+                eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED));
+    }
+
+    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+    @Test
+    public void testEventLogging_bubbleBar_updateBubble() {
+        mBubbleProperties.mIsBubbleBarEnabled = true;
+        mPositioner.setIsLargeScreen(true);
+        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+        mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+        mEntryListener.onEntryAdded(mRow);
+        // Mark the notification as updated
+        NotificationEntryHelper.modifyRanking(mRow).setTextChanged(true).build();
+        mEntryListener.onEntryUpdated(mRow, /* fromSystem= */ true);
+
+        verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+                eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_UPDATED));
+    }
+
+    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+    @Test
+    public void testEventLogging_bubbleBar_dragBubbleToDismiss() {
+        mBubbleProperties.mIsBubbleBarEnabled = true;
+        mPositioner.setIsLargeScreen(true);
+        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+        mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+        mEntryListener.onEntryAdded(mRow);
+        mBubbleController.dragBubbleToDismiss(mRow.getKey(), 1L);
+
+        verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+                eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE));
+    }
+
     /** Creates a bubble using the userId and package. */
     private Bubble createBubble(int userId, String pkg) {
         final UserHandle userHandle = new UserHandle(userId);
@@ -2655,6 +2703,10 @@
         assertThat(mSysUiStateBubblesManageMenuExpanded).isEqualTo(manageMenuExpanded);
     }
 
+    private Bubble eqBubbleWithKey(String key) {
+        return argThat(b -> b.getKey().equals(key));
+    }
+
     private static class FakeBubbleStateListener implements Bubbles.BubbleStateListener {
 
         int mStateChangeCalls = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/wmshell/OWNERS
new file mode 100644
index 0000000..eae8629
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/OWNERS
@@ -0,0 +1,5 @@
+# Bubbles team
+madym@google.com
+atsjenk@google.com
+liranb@google.com
+mpodolian@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index baaf604..703e2d1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -49,8 +49,6 @@
     private val _isAlternateBouncerVisible = MutableStateFlow(false)
     override val alternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
     override var lastAlternateBouncerVisibleTime: Long = 0L
-    private val _isAlternateBouncerUIAvailable = MutableStateFlow<Boolean>(false)
-    override val alternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow()
     override val lastShownSecurityMode: MutableStateFlow<KeyguardSecurityModel.SecurityMode> =
         MutableStateFlow(KeyguardSecurityModel.SecurityMode.Invalid)
     override var bouncerDismissActionModel: BouncerDismissActionModel? = null
@@ -63,10 +61,6 @@
         _isAlternateBouncerVisible.value = isVisible
     }
 
-    override fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
-        _isAlternateBouncerUIAvailable.value = isAvailable
-    }
-
     override fun setPrimaryShow(isShowing: Boolean) {
         _primaryBouncerShow.value = isShowing
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
index 63323b2..8bbb8a0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
@@ -16,33 +16,23 @@
 
 package com.android.systemui.bouncer.domain.interactor
 
-import com.android.keyguard.keyguardUpdateMonitor
 import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
 import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryBiometricsAllowedInteractor
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
-import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.statusbar.policy.keyguardStateController
-import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.systemClock
 
 val Kosmos.alternateBouncerInteractor: AlternateBouncerInteractor by
     Kosmos.Fixture {
         AlternateBouncerInteractor(
-            statusBarStateController = statusBarStateController,
-            keyguardStateController = keyguardStateController,
             bouncerRepository = keyguardBouncerRepository,
             fingerprintPropertyRepository = fingerprintPropertyRepository,
-            biometricSettingsRepository = biometricSettingsRepository,
             systemClock = systemClock,
-            keyguardUpdateMonitor = keyguardUpdateMonitor,
             deviceEntryBiometricsAllowedInteractor = { deviceEntryBiometricsAllowedInteractor },
             keyguardInteractor = { keyguardInteractor },
             keyguardTransitionInteractor = { keyguardTransitionInteractor },
@@ -54,21 +44,9 @@
 fun Kosmos.givenCanShowAlternateBouncer() {
     this.givenAlternateBouncerSupported()
     this.keyguardBouncerRepository.setPrimaryShow(false)
-    this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
-    this.biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
     this.deviceEntryFaceAuthRepository.setLockedOut(false)
-    whenever(this.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
-    whenever(this.keyguardStateController.isUnlocked).thenReturn(false)
 }
 
 fun Kosmos.givenAlternateBouncerSupported() {
-    if (DeviceEntryUdfpsRefactor.isEnabled) {
-        this.fingerprintPropertyRepository.supportsUdfps()
-    } else {
-        this.keyguardBouncerRepository.setAlternateBouncerUIAvailable(true)
-    }
-}
-
-fun Kosmos.givenCannotShowAlternateBouncer() {
-    this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+    this.fingerprintPropertyRepository.supportsUdfps()
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index fcc83b3..78ea700 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -53,6 +53,10 @@
     private val displayAdditionEventFlow = MutableSharedFlow<Display?>(replay = 0)
     private val displayRemovalEventFlow = MutableSharedFlow<Int>(replay = 0)
 
+    suspend fun addDisplay(displayId: Int, type: Int = Display.TYPE_EXTERNAL) {
+        addDisplay(display(type, id = displayId))
+    }
+
     suspend fun addDisplay(display: Display) {
         flow.value += display
         displayAdditionEventFlow.emit(display)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt
index 4ccee6f..2aa2744 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt
@@ -22,18 +22,16 @@
 import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 
 val Kosmos.deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor by
     Kosmos.Fixture {
         DeviceEntrySideFpsOverlayInteractor(
-            applicationScope = testScope.backgroundScope,
             context = applicationContext,
             deviceEntryFingerprintAuthRepository = deviceEntryFingerprintAuthRepository,
             sceneInteractor = sceneInteractor,
             primaryBouncerInteractor = primaryBouncerInteractor,
             alternateBouncerInteractor = alternateBouncerInteractor,
-            keyguardUpdateMonitor = keyguardUpdateMonitor
+            keyguardUpdateMonitor = keyguardUpdateMonitor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index ddcc6d6..b9f0c9a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -37,7 +37,7 @@
 import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.deviceProvisionedController
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
@@ -67,7 +67,7 @@
             mock<KeyguardStateController>(),
             statusBarStateController,
             statusBarKeyguardViewManager,
-            mock<StatusBarWindowController>(),
+            mock<StatusBarWindowControllerStore>(),
             deviceProvisionedController,
             mock<NotificationShadeWindowController>(),
             0,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModelKosmos.kt
similarity index 85%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModelKosmos.kt
index c0d65a0..2316a2f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/demo/ui/viewmodel/DemoNotifChipViewModelKosmos.kt
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel
+package com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel
 
 import android.content.packageManager
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.commandline.commandRegistry
 import com.android.systemui.util.time.fakeSystemClock
 
-val Kosmos.demoRonChipViewModel: DemoRonChipViewModel by
+val Kosmos.demoNotifChipViewModel: DemoNotifChipViewModel by
     Kosmos.Fixture {
-        DemoRonChipViewModel(
+        DemoNotifChipViewModel(
             commandRegistry = commandRegistry,
             packageManager = packageManager,
             systemClock = fakeSystemClock,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
new file mode 100644
index 0000000..af24c37
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.chips.notification.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+
+val Kosmos.notifChipsViewModel: NotifChipsViewModel by
+    Kosmos.Fixture { NotifChipsViewModel(activeNotificationsInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index 5382c1c..0300bf4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -20,7 +20,8 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.statusbar.chips.call.ui.viewmodel.callChipViewModel
 import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.castToOtherDeviceChipViewModel
-import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.demoRonChipViewModel
+import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.demoNotifChipViewModel
+import com.android.systemui.statusbar.chips.notification.ui.viewmodel.notifChipsViewModel
 import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.screenRecordChipViewModel
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
 import com.android.systemui.statusbar.chips.statusBarChipsLogger
@@ -33,7 +34,8 @@
             shareToAppChipViewModel = shareToAppChipViewModel,
             castToOtherDeviceChipViewModel = castToOtherDeviceChipViewModel,
             callChipViewModel = callChipViewModel,
-            demoRonChipViewModel = demoRonChipViewModel,
+            notifChipsViewModel = notifChipsViewModel,
+            demoNotifChipViewModel = demoNotifChipViewModel,
             logger = statusBarChipsLogger,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
new file mode 100644
index 0000000..73ed228
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.core
+
+import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
+import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
+
+class FakeStatusBarInitializerFactory(
+    private val statusBarViewController: PhoneStatusBarViewController,
+    private val statusBarTransitions: PhoneStatusBarTransitions,
+) : StatusBarInitializer.Factory {
+
+    override fun create(displayId: Int): StatusBarInitializer =
+        FakeStatusBarInitializer(statusBarViewController, statusBarTransitions)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
index d103200..7ad715b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.statusbar.core
 
+import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.statusbar.phone.phoneStatusBarTransitions
 import com.android.systemui.statusbar.phone.phoneStatusBarViewController
 
@@ -26,3 +28,20 @@
     }
 
 var Kosmos.statusBarInitializer by Kosmos.Fixture { fakeStatusBarInitializer }
+
+val Kosmos.fakeStatusBarInitializerFactory by
+    Kosmos.Fixture {
+        FakeStatusBarInitializerFactory(phoneStatusBarViewController, phoneStatusBarTransitions)
+    }
+
+var Kosmos.statusBarInitializerFactory: StatusBarInitializer.Factory by
+    Kosmos.Fixture { fakeStatusBarInitializerFactory }
+
+val Kosmos.multiDisplayStatusBarInitializerStore by
+    Kosmos.Fixture {
+        MultiDisplayStatusBarInitializerStore(
+            applicationCoroutineScope,
+            fakeStatusBarInitializerFactory,
+            displayRepository,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
index c53e44d..54de293 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
@@ -28,7 +28,7 @@
 import com.android.systemui.statusbar.mockNotificationRemoteInputManager
 import com.android.systemui.statusbar.phone.mockAutoHideController
 import com.android.systemui.statusbar.window.data.repository.statusBarWindowStateRepositoryStore
-import com.android.systemui.statusbar.window.fakeStatusBarWindowController
+import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
 import com.android.wm.shell.bubbles.bubblesOptional
 
 val Kosmos.statusBarOrchestrator by
@@ -36,8 +36,8 @@
         StatusBarOrchestrator(
             applicationCoroutineScope,
             fakeStatusBarInitializer,
-            fakeStatusBarWindowController,
             fakeStatusBarModeRepository,
+            fakeStatusBarWindowControllerStore,
             mockDemoModeController,
             mockPluginDependencyProvider,
             mockAutoHideController,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index fc4f05d..7f4c670 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -69,6 +69,9 @@
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
+import com.android.systemui.statusbar.notification.row.icon.AppIconProviderImpl
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProviderImpl
+import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
 import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -99,7 +102,7 @@
 class ExpandableNotificationRowBuilder(
     private val context: Context,
     dependency: TestableDependency,
-    private val featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic()
+    private val featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic(),
 ) {
 
     private val mMockLogger: ExpandableNotificationRowLogger
@@ -161,21 +164,21 @@
                         DeviceConfig.NAMESPACE_SYSTEMUI,
                         SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP,
                         "true",
-                        true
+                        true,
                     )
                     setProperty(
                         DeviceConfig.NAMESPACE_SYSTEMUI,
                         SystemUiDeviceConfigFlags.SSIN_ENABLED,
                         "true",
-                        true
+                        true,
                     )
                     setProperty(
                         DeviceConfig.NAMESPACE_SYSTEMUI,
                         SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P,
                         "false",
-                        true
+                        true,
                     )
-                }
+                },
             )
         val remoteViewsFactories = getNotifRemoteViewsFactoryContainer(featureFlags)
         val remoteInputManager = Mockito.mock(NotificationRemoteInputManager::class.java, STUB_ONLY)
@@ -192,21 +195,21 @@
                             Mockito.mock(KeyguardDismissUtil::class.java, STUB_ONLY),
                         remoteInputManager = remoteInputManager,
                         smartReplyController = mSmartReplyController,
-                        context = context
+                        context = context,
                     ),
                 smartActionsInflater =
                     SmartActionInflaterImpl(
                         constants = mSmartReplyConstants,
                         activityStarter = Mockito.mock(ActivityStarter::class.java, STUB_ONLY),
                         smartReplyController = mSmartReplyController,
-                        headsUpManager = mHeadsUpManager
-                    )
+                        headsUpManager = mHeadsUpManager,
+                    ),
             )
         val notifLayoutInflaterFactoryProvider =
             object : NotifLayoutInflaterFactory.Provider {
                 override fun provide(
                     row: ExpandableNotificationRow,
-                    layoutType: Int
+                    layoutType: Int,
                 ): NotifLayoutInflaterFactory =
                     NotifLayoutInflaterFactory(row, layoutType, remoteViewsFactories)
             }
@@ -270,14 +273,14 @@
         whenever(
                 mOnUserInteractionCallback.registerFutureDismissal(
                     ArgumentMatchers.any(),
-                    ArgumentMatchers.anyInt()
+                    ArgumentMatchers.anyInt(),
                 )
             )
             .thenReturn(mFutureDismissalRunnable)
     }
 
     private fun getNotifRemoteViewsFactoryContainer(
-        featureFlags: FeatureFlags,
+        featureFlags: FeatureFlags
     ): NotifRemoteViewsFactoryContainer {
         return NotifRemoteViewsFactoryContainerImpl(
             featureFlags,
@@ -285,6 +288,10 @@
             BigPictureLayoutInflaterFactory(),
             NotificationOptimizedLinearLayoutFactory(),
             { Mockito.mock(NotificationViewFlipperFactory::class.java) },
+            NotificationRowIconViewInflaterFactory(
+                AppIconProviderImpl(context),
+                NotificationIconStyleProviderImpl(),
+            ),
         )
     }
 
@@ -293,7 +300,7 @@
             NotificationChannel(
                 notification.channelId,
                 notification.channelId,
-                NotificationManager.IMPORTANCE_DEFAULT
+                NotificationManager.IMPORTANCE_DEFAULT,
             )
         channel.isBlockable = true
         val entry =
@@ -321,7 +328,7 @@
 
     private fun generateRow(
         entry: NotificationEntry,
-        @InflationFlag extraInflationFlags: Int
+        @InflationFlag extraInflationFlags: Int,
     ): ExpandableNotificationRow {
         // NOTE: This flag is read when the ExpandableNotificationRow is inflated, so it needs to be
         //  set, but we do not want to override an existing value that is needed by a specific test.
@@ -329,7 +336,7 @@
         val rowInflaterTask =
             RowInflaterTask(
                 mFakeSystemClock,
-                Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY)
+                Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY),
             )
         val row = rowInflaterTask.inflateSynchronously(context, null, entry)
 
@@ -364,7 +371,7 @@
             mSmartReplyController,
             featureFlags,
             Mockito.mock(IStatusBarService::class.java, STUB_ONLY),
-            Mockito.mock(UiEventLogger::class.java, STUB_ONLY)
+            Mockito.mock(UiEventLogger::class.java, STUB_ONLY),
         )
         row.setAboveShelfChangedListener { aboveShelf: Boolean -> }
         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/AppIconProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/AppIconProviderKosmos.kt
new file mode 100644
index 0000000..08c6bba
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/AppIconProviderKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.appIconProvider by Kosmos.Fixture { AppIconProviderImpl(applicationContext) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/NotificationIconStyleProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/NotificationIconStyleProviderKosmos.kt
new file mode 100644
index 0000000..611c90a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/NotificationIconStyleProviderKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.notificationIconStyleProvider by Kosmos.Fixture { NotificationIconStyleProviderImpl() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt
index d19e322..35f95b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowControllerStore.kt
@@ -22,10 +22,10 @@
 
     private val perDisplayControllers = mutableMapOf<Int, FakeStatusBarWindowController>()
 
-    override val defaultDisplay
+    override val defaultDisplay: FakeStatusBarWindowController
         get() = forDisplay(Display.DEFAULT_DISPLAY)
 
-    override fun forDisplay(displayId: Int): StatusBarWindowController {
+    override fun forDisplay(displayId: Int): FakeStatusBarWindowController {
         return perDisplayControllers.computeIfAbsent(displayId) { FakeStatusBarWindowController() }
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
index 6c6f243..78caf93 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
@@ -20,7 +20,8 @@
 
 val Kosmos.fakeStatusBarWindowController by Kosmos.Fixture { FakeStatusBarWindowController() }
 
-var Kosmos.statusBarWindowController by Kosmos.Fixture { fakeStatusBarWindowController }
+var Kosmos.statusBarWindowController: StatusBarWindowController by
+    Kosmos.Fixture { fakeStatusBarWindowController }
 
 val Kosmos.fakeStatusBarWindowControllerStore by
     Kosmos.Fixture { FakeStatusBarWindowControllerStore() }
diff --git a/packages/Vcn/OWNERS b/packages/Vcn/OWNERS
new file mode 100644
index 0000000..ff2146e
--- /dev/null
+++ b/packages/Vcn/OWNERS
@@ -0,0 +1,6 @@
+evitayan@google.com
+nharold@google.com
+benedictwong@google.com #{LAST_RESORT_SUGGESTION}
+yangji@google.com #{LAST_RESORT_SUGGESTION}
+
+include platform/packages/modules/common:/MODULES_OWNERS
\ No newline at end of file
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 8896d77..8e884bc 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -8,7 +8,7 @@
 
     // OWNER: g/ravenwood
     // Bug component: 25698
-    default_team: "trendy_team_framework_backstage_power",
+    default_team: "trendy_team_ravenwood",
 }
 
 filegroup {
@@ -372,6 +372,7 @@
 android_ravenwood_libgroup {
     name: "ravenwood-runtime",
     data: [
+        ":system-build.prop",
         ":framework-res",
         ":ravenwood-empty-res",
         ":framework-platform-compat-config",
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 908e590..24950e6 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -20,12 +20,14 @@
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.getRavenwoodRuntimePath;
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.ResourcesManager;
@@ -81,6 +83,8 @@
     private static final String MAIN_THREAD_NAME = "RavenwoodMain";
     private static final String RAVENWOOD_NATIVE_SYSPROP_NAME = "ravenwood_sysprop";
     private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime";
+    private static final String RAVENWOOD_BUILD_PROP =
+            getRavenwoodRuntimePath() + "ravenwood-data/build.prop";
 
     /**
      * When enabled, attempt to dump all thread stacks just before we hit the
@@ -158,7 +162,8 @@
         System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME));
 
         // Do the basic set up for the android sysprops.
-        setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
+        RavenwoodSystemProperties.initialize(RAVENWOOD_BUILD_PROP);
+        setSystemProperties(null);
 
         // Make sure libandroid_runtime is loaded.
         RavenwoodNativeLoader.loadFrameworkNativeCode();
@@ -329,13 +334,17 @@
         LocalServices.removeAllServicesForTest();
         ServiceManager.reset$ravenwood();
 
-        setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
+        setSystemProperties(null);
         if (sOriginalIdentityToken != -1) {
             Binder.restoreCallingIdentity(sOriginalIdentityToken);
         }
         android.os.Process.reset$ravenwood();
 
-        ResourcesManager.setInstance(null); // Better structure needed.
+        try {
+            ResourcesManager.setInstance(null); // Better structure needed.
+        } catch (Exception e) {
+            // AOSP-CHANGE: AOSP doesn't support resources yet.
+        }
 
         if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
             maybeThrowPendingUncaughtException(true);
@@ -384,9 +393,10 @@
     /**
      * Set the current configuration to the actual SystemProperties.
      */
-    private static void setSystemProperties(RavenwoodSystemProperties systemProperties) {
+    private static void setSystemProperties(@Nullable RavenwoodSystemProperties systemProperties) {
         SystemProperties.clearChangeCallbacksForTest();
         RavenwoodRuntimeNative.clearSystemProperties();
+        if (systemProperties == null) systemProperties = new RavenwoodSystemProperties();
         sProps = new RavenwoodSystemProperties(systemProperties, true);
         for (var entry : systemProperties.getValues().entrySet()) {
             RavenwoodRuntimeNative.setSystemProperty(entry.getKey(), entry.getValue());
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
index f1e1ef6..ced1519 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
@@ -18,12 +18,94 @@
 
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_SYSPROP;
 
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 public class RavenwoodSystemProperties {
+    private static final String TAG = "RavenwoodSystemProperties";
+
+    private static final Map<String, String> sDefaultValues = new HashMap<>();
+
+    private static final String[] PARTITIONS = {
+            "bootimage",
+            "odm",
+            "product",
+            "system",
+            "system_ext",
+            "vendor",
+            "vendor_dlkm",
+    };
+
+    /**
+     * More info about property file loading: system/core/init/property_service.cpp
+     * In the following logic, the only partition we would need to consider is "system",
+     * since we only read from system-build.prop
+     */
+    static void initialize(String propFile) {
+        // Load all properties from build.prop
+        try {
+            Files.readAllLines(Path.of(propFile)).stream()
+                    .map(String::trim)
+                    .filter(s -> !s.startsWith("#"))
+                    .map(s -> s.split("\\s*=\\s*", 2))
+                    .filter(a -> a.length == 2)
+                    .forEach(a -> sDefaultValues.put(a[0], a[1]));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        // If ro.product.${name} is not set, derive from ro.product.${partition}.${name}
+        // If ro.product.cpu.abilist* is not set, derive from ro.${partition}.product.cpu.abilist*
+        for (var entry : Set.copyOf(sDefaultValues.entrySet())) {
+            final String key;
+            if (entry.getKey().startsWith("ro.product.system.")) {
+                var name = entry.getKey().substring(18);
+                key = "ro.product." + name;
+
+            } else if (entry.getKey().startsWith("ro.system.product.cpu.abilist")) {
+                var name = entry.getKey().substring(22);
+                key = "ro.product.cpu." + name;
+            } else {
+                continue;
+            }
+            if (!sDefaultValues.containsKey(key)) {
+                sDefaultValues.put(key, entry.getValue());
+            }
+        }
+
+        // Some other custom values
+        sDefaultValues.put("ro.board.first_api_level", "1");
+        sDefaultValues.put("ro.product.first_api_level", "1");
+        sDefaultValues.put("ro.soc.manufacturer", "Android");
+        sDefaultValues.put("ro.soc.model", "Ravenwood");
+        sDefaultValues.put(RAVENWOOD_SYSPROP, "1");
+
+        // Log all values
+        sDefaultValues.forEach((key, value) -> RavenwoodCommonUtils.log(TAG, key + "=" + value));
+
+        // Copy ro.product.* and ro.build.* to all partitions, just in case
+        // We don't want to log these because these are just a lot of duplicate values
+        for (var entry : Set.copyOf(sDefaultValues.entrySet())) {
+            var key = entry.getKey();
+            if (key.startsWith("ro.product.") || key.startsWith("ro.build.")) {
+                var name = key.substring(3);
+                for (String partition : PARTITIONS) {
+                    var newKey = "ro." + partition + "." + name;
+                    if (!sDefaultValues.containsKey(newKey)) {
+                        sDefaultValues.put(newKey, entry.getValue());
+                    }
+                }
+            }
+        }
+    }
+
     private volatile boolean mIsImmutable;
 
     private final Map<String, String> mValues = new HashMap<>();
@@ -35,47 +117,15 @@
     private final Set<String> mKeyWritable = new HashSet<>();
 
     public RavenwoodSystemProperties() {
-        // TODO: load these values from build.prop generated files
-        setValueForPartitions("product.brand", "Android");
-        setValueForPartitions("product.device", "Ravenwood");
-        setValueForPartitions("product.manufacturer", "Android");
-        setValueForPartitions("product.model", "Ravenwood");
-        setValueForPartitions("product.name", "Ravenwood");
-
-        setValueForPartitions("product.cpu.abilist", "x86_64");
-        setValueForPartitions("product.cpu.abilist32", "");
-        setValueForPartitions("product.cpu.abilist64", "x86_64");
-
-        setValueForPartitions("build.date", "Thu Jan 01 00:00:00 GMT 2024");
-        setValueForPartitions("build.date.utc", "1704092400");
-        setValueForPartitions("build.id", "MAIN");
-        setValueForPartitions("build.tags", "dev-keys");
-        setValueForPartitions("build.type", "userdebug");
-        setValueForPartitions("build.version.all_codenames", "REL");
-        setValueForPartitions("build.version.codename", "REL");
-        setValueForPartitions("build.version.incremental", "userdebug.ravenwood.20240101");
-        setValueForPartitions("build.version.known_codenames", "REL");
-        setValueForPartitions("build.version.release", "14");
-        setValueForPartitions("build.version.release_or_codename", "VanillaIceCream");
-        setValueForPartitions("build.version.sdk", "34");
-
-        setValue("ro.board.first_api_level", "1");
-        setValue("ro.product.first_api_level", "1");
-
-        setValue("ro.soc.manufacturer", "Android");
-        setValue("ro.soc.model", "Ravenwood");
-
-        setValue("ro.debuggable", "1");
-
-        setValue(RAVENWOOD_SYSPROP, "1");
+        mValues.putAll(sDefaultValues);
     }
 
     /** Copy constructor */
     public RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable) {
-        this.mKeyReadable.addAll(source.mKeyReadable);
-        this.mKeyWritable.addAll(source.mKeyWritable);
-        this.mValues.putAll(source.mValues);
-        this.mIsImmutable = immutable;
+        mKeyReadable.addAll(source.mKeyReadable);
+        mKeyWritable.addAll(source.mKeyWritable);
+        mValues.putAll(source.mValues);
+        mIsImmutable = immutable;
     }
 
     public Map<String, String> getValues() {
@@ -123,36 +173,12 @@
         return mKeyWritable.contains(key);
     }
 
-    private static final String[] PARTITIONS = {
-            "bootimage",
-            "odm",
-            "product",
-            "system",
-            "system_ext",
-            "vendor",
-            "vendor_dlkm",
-    };
-
     private void ensureNotImmutable() {
         if (mIsImmutable) {
             throw new RuntimeException("Unable to update immutable instance");
         }
     }
 
-    /**
-     * Set the given property for all possible partitions where it could be defined. For
-     * example, the value of {@code ro.build.type} is typically also mirrored under
-     * {@code ro.system.build.type}, etc.
-     */
-    private void setValueForPartitions(String key, String value) {
-        ensureNotImmutable();
-
-        setValue("ro." + key, value);
-        for (String partition : PARTITIONS) {
-            setValue("ro." + partition + "." + key, value);
-        }
-    }
-
     public void setValue(String key, Object value) {
         ensureNotImmutable();
 
@@ -195,11 +221,4 @@
             return key;
         }
     }
-
-    /**
-     * Return an immutable, default instance.
-     */
-    // Create a default instance, and make an immutable copy of it.
-    public static final RavenwoodSystemProperties DEFAULT_VALUES =
-            new RavenwoodSystemProperties(new RavenwoodSystemProperties(), true);
 }
diff --git a/ravenwood/minimum-test/Android.bp b/ravenwood/tests/minimum-test/Android.bp
similarity index 100%
rename from ravenwood/minimum-test/Android.bp
rename to ravenwood/tests/minimum-test/Android.bp
diff --git a/ravenwood/minimum-test/README.md b/ravenwood/tests/minimum-test/README.md
similarity index 100%
rename from ravenwood/minimum-test/README.md
rename to ravenwood/tests/minimum-test/README.md
diff --git a/ravenwood/minimum-test/test/com/android/ravenwoodtest/RavenwoodMinimumTest.java b/ravenwood/tests/minimum-test/test/com/android/ravenwoodtest/RavenwoodMinimumTest.java
similarity index 100%
rename from ravenwood/minimum-test/test/com/android/ravenwoodtest/RavenwoodMinimumTest.java
rename to ravenwood/tests/minimum-test/test/com/android/ravenwoodtest/RavenwoodMinimumTest.java
diff --git a/ravenwood/mockito/Android.bp b/ravenwood/tests/mockito/Android.bp
similarity index 100%
rename from ravenwood/mockito/Android.bp
rename to ravenwood/tests/mockito/Android.bp
diff --git a/ravenwood/mockito/AndroidManifest.xml b/ravenwood/tests/mockito/AndroidManifest.xml
similarity index 100%
rename from ravenwood/mockito/AndroidManifest.xml
rename to ravenwood/tests/mockito/AndroidManifest.xml
diff --git a/ravenwood/mockito/AndroidTest.xml b/ravenwood/tests/mockito/AndroidTest.xml
similarity index 100%
rename from ravenwood/mockito/AndroidTest.xml
rename to ravenwood/tests/mockito/AndroidTest.xml
diff --git a/ravenwood/mockito/README.md b/ravenwood/tests/mockito/README.md
similarity index 100%
rename from ravenwood/mockito/README.md
rename to ravenwood/tests/mockito/README.md
diff --git a/ravenwood/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoDeviceOnlyTest.java b/ravenwood/tests/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoDeviceOnlyTest.java
similarity index 100%
rename from ravenwood/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoDeviceOnlyTest.java
rename to ravenwood/tests/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoDeviceOnlyTest.java
diff --git a/ravenwood/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoRavenwoodOnlyTest.java b/ravenwood/tests/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoRavenwoodOnlyTest.java
similarity index 100%
rename from ravenwood/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoRavenwoodOnlyTest.java
rename to ravenwood/tests/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoRavenwoodOnlyTest.java
diff --git a/ravenwood/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoTest.java b/ravenwood/tests/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoTest.java
similarity index 100%
rename from ravenwood/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoTest.java
rename to ravenwood/tests/mockito/test/com/android/ravenwoodtest/mockito/RavenwoodMockitoTest.java
diff --git a/ravenwood/resapk_test/Android.bp b/ravenwood/tests/resapk_test/Android.bp
similarity index 100%
rename from ravenwood/resapk_test/Android.bp
rename to ravenwood/tests/resapk_test/Android.bp
diff --git a/ravenwood/resapk_test/apk/Android.bp b/ravenwood/tests/resapk_test/apk/Android.bp
similarity index 100%
rename from ravenwood/resapk_test/apk/Android.bp
rename to ravenwood/tests/resapk_test/apk/Android.bp
diff --git a/ravenwood/resapk_test/apk/AndroidManifest.xml b/ravenwood/tests/resapk_test/apk/AndroidManifest.xml
similarity index 100%
rename from ravenwood/resapk_test/apk/AndroidManifest.xml
rename to ravenwood/tests/resapk_test/apk/AndroidManifest.xml
diff --git a/ravenwood/resapk_test/apk/res/values/strings.xml b/ravenwood/tests/resapk_test/apk/res/values/strings.xml
similarity index 100%
rename from ravenwood/resapk_test/apk/res/values/strings.xml
rename to ravenwood/tests/resapk_test/apk/res/values/strings.xml
diff --git a/ravenwood/resapk_test/test/com/android/ravenwoodtest/resapk_test/RavenwoodResApkTest.java b/ravenwood/tests/resapk_test/test/com/android/ravenwoodtest/resapk_test/RavenwoodResApkTest.java
similarity index 100%
rename from ravenwood/resapk_test/test/com/android/ravenwoodtest/resapk_test/RavenwoodResApkTest.java
rename to ravenwood/tests/resapk_test/test/com/android/ravenwoodtest/resapk_test/RavenwoodResApkTest.java
diff --git a/ravenwood/runtime-test/Android.bp b/ravenwood/tests/runtime-test/Android.bp
similarity index 100%
rename from ravenwood/runtime-test/Android.bp
rename to ravenwood/tests/runtime-test/Android.bp
diff --git a/ravenwood/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsConstantsTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsConstantsTest.java
similarity index 100%
rename from ravenwood/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsConstantsTest.java
rename to ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsConstantsTest.java
diff --git a/ravenwood/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java
similarity index 100%
rename from ravenwood/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java
rename to ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java
diff --git a/ravenwood/services-test/Android.bp b/ravenwood/tests/services-test/Android.bp
similarity index 100%
rename from ravenwood/services-test/Android.bp
rename to ravenwood/tests/services-test/Android.bp
diff --git a/ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesDependenciesTest.java b/ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesDependenciesTest.java
similarity index 100%
rename from ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesDependenciesTest.java
rename to ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesDependenciesTest.java
diff --git a/ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java b/ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java
similarity index 100%
rename from ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java
rename to ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java
diff --git a/ravenwood/tools/hoststubgen/.gitignore b/ravenwood/tools/hoststubgen/.gitignore
new file mode 100644
index 0000000..82158c9
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/.gitignore
@@ -0,0 +1,4 @@
+framework-all-stub-out
+out/
+*-out/
+*.log
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/ravenwood/tools/hoststubgen/Android.bp
similarity index 98%
rename from tools/hoststubgen/hoststubgen/Android.bp
rename to ravenwood/tools/hoststubgen/Android.bp
index 4920f7b4..a5ff496 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/ravenwood/tools/hoststubgen/Android.bp
@@ -8,7 +8,7 @@
 
     // OWNER: g/ravenwood
     // Bug component: 25698
-    default_team: "trendy_team_framework_backstage_power",
+    default_team: "trendy_team_ravenwood",
 }
 
 // Visibility only for ravenwood prototype uses.
diff --git a/tools/hoststubgen/README.md b/ravenwood/tools/hoststubgen/README.md
similarity index 84%
rename from tools/hoststubgen/README.md
rename to ravenwood/tools/hoststubgen/README.md
index 1a895dc..615e767 100644
--- a/tools/hoststubgen/README.md
+++ b/ravenwood/tools/hoststubgen/README.md
@@ -11,7 +11,7 @@
 
 - HostStubGen itself is design to be agnostic to Android. It doesn't use any Android APIs
 (hidden or not). But it may use Android specific knowledge -- e.g. as of now,
-AndroidHeuristicsFilter has hardcoded heuristics to detect AIDL generated classes. 
+AndroidHeuristicsFilter has hardcoded heuristics to detect AIDL generated classes.
 
 - `test-tiny-framework/` contains basic tests that are agnostic to Android.
 
@@ -20,19 +20,16 @@
 
 ## Directories and files
 
-- `hoststubgen/`
-  Contains source code of the "hoststubgen" tool and relevant code
+- `src/`
 
-  - `src/`
+  HostStubGen tool source code.
 
-    HostStubGen tool source code.
+- `annotations-src/` See `Android.bp`.
+- `helper-framework-buildtime-src/` See `Android.bp`.
+- `helper-framework-runtime-src/` See `Android.bp`.
+- `helper-runtime-src/` See `Android.bp`.
 
-  - `annotations-src/` See `Android.bp`.
-  - `helper-framework-buildtime-src/` See `Android.bp`.
-  - `helper-framework-runtime-src/` See `Android.bp`.
-  - `helper-runtime-src/` See `Android.bp`.
-
-  - `test-tiny-framework/` See `README.md` in it.
+- `test-tiny-framework/` See `README.md` in it.
 
 - `scripts`
   - `dump-jar.sh`
@@ -78,4 +75,4 @@
 
 - At some point, we can move or delete all Android specific code to `frameworks/base/ravenwood`.
   - `helper-framework-*-src` should be moved to `frameworks/base/ravenwood`
-  - `test-framework` should be deleted.
\ No newline at end of file
+  - `test-framework` should be deleted.
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerKeep.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerKeep.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerKeep.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerKeep.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java b/ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
rename to ravenwood/tools/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
diff --git a/tools/hoststubgen/common.sh b/ravenwood/tools/hoststubgen/common.sh
similarity index 100%
rename from tools/hoststubgen/common.sh
rename to ravenwood/tools/hoststubgen/common.sh
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/ravenwood/tools/hoststubgen/framework-policy-override.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/framework-policy-override.txt
rename to ravenwood/tools/hoststubgen/framework-policy-override.txt
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsIgnore.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsIgnore.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsIgnore.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsIgnore.java
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsKeep.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsKeep.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsKeep.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsKeep.java
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsThrow.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsThrow.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsThrow.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsThrow.java
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
rename to ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/ravenwood/tools/hoststubgen/hoststubgen-standard-options.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
rename to ravenwood/tools/hoststubgen/hoststubgen-standard-options.txt
diff --git a/tools/hoststubgen/hoststubgen/invoketest/Android.bp b/ravenwood/tools/hoststubgen/invoketest/Android.bp
similarity index 100%
rename from tools/hoststubgen/hoststubgen/invoketest/Android.bp
rename to ravenwood/tools/hoststubgen/invoketest/Android.bp
diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/ravenwood/tools/hoststubgen/invoketest/hoststubgen-invoke-test.sh
similarity index 100%
rename from tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
rename to ravenwood/tools/hoststubgen/invoketest/hoststubgen-invoke-test.sh
diff --git a/tools/hoststubgen/hoststubgen/jarjar-rules.txt b/ravenwood/tools/hoststubgen/jarjar-rules.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/jarjar-rules.txt
rename to ravenwood/tools/hoststubgen/jarjar-rules.txt
diff --git a/tools/hoststubgen/scripts/Android.bp b/ravenwood/tools/hoststubgen/scripts/Android.bp
similarity index 100%
rename from tools/hoststubgen/scripts/Android.bp
rename to ravenwood/tools/hoststubgen/scripts/Android.bp
diff --git a/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh b/ravenwood/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
similarity index 100%
rename from tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
rename to ravenwood/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
diff --git a/tools/hoststubgen/scripts/dump-jar b/ravenwood/tools/hoststubgen/scripts/dump-jar
similarity index 100%
rename from tools/hoststubgen/scripts/dump-jar
rename to ravenwood/tools/hoststubgen/scripts/dump-jar
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
rename to ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
similarity index 98%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
rename to ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
index ba2c869..1570549 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
@@ -16,7 +16,7 @@
     static_libs: [
         "hoststubgen-annotations",
     ],
-    visibility: ["//frameworks/base/tools/hoststubgen:__subpackages__"],
+    visibility: ["//frameworks/base/ravenwood/tools/hoststubgen:__subpackages__"],
 }
 
 // Create stub/impl jars from "hoststubgen-test-tiny-framework", using the following 3 rules.
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml b/ravenwood/tools/hoststubgen/test-tiny-framework/AndroidTest-host.xml
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml
rename to ravenwood/tools/hoststubgen/test-tiny-framework/AndroidTest-host.xml
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md b/ravenwood/tools/hoststubgen/test-tiny-framework/README.md
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
rename to ravenwood/tools/hoststubgen/test-tiny-framework/README.md
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
rename to ravenwood/tools/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh b/ravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
rename to ravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
rename to ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
rename to ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
rename to ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
rename to ravenwood/tools/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/ravenwood/tools/hoststubgen/test-tiny-framework/run-test-manually.sh
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
rename to ravenwood/tools/hoststubgen/test-tiny-framework/run-test-manually.sh
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C1.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C1.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C1.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C1.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C2.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C2.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C2.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C2.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C3.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C3.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C3.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/C3.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CB.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CB.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CB.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/CB.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_None.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_None.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_None.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/Class_None.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I1.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I1.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I1.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I1.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I2.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I2.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I2.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I2.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I3.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I3.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I3.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/I3.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IA.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IA.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IA.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IA.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IB.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IB.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IB.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/subclasstest/IB.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
rename to ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt b/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt
rename to ravenwood/tools/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt b/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
rename to ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt b/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt
rename to ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt b/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt
similarity index 100%
rename from tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt
rename to ravenwood/tools/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ba84485..1803424 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -49,3 +49,10 @@
   description: "Include the session id into the FillEventHistory events as part of ClientState"
   bug: "333927465"
 }
+
+flag {
+  name: "highlight_autofill_single_field"
+  namespace: "autofill"
+  description: "Highlight single field after autofill selection"
+  bug: "41496744"
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2fa0e0d..8f12b1d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -39,6 +39,7 @@
 import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
 import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
+import static android.service.autofill.Flags.highlightAutofillSingleField;
 import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
@@ -49,7 +50,6 @@
 import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
-
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_EXPLICITLY_REQUESTED;
 import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER;
@@ -104,7 +104,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Activity;
 import android.app.ActivityTaskManager;
 import android.app.IAssistDataReceiver;
 import android.app.PendingIntent;
@@ -143,7 +142,6 @@
 import android.service.assist.classification.FieldClassificationRequest;
 import android.service.assist.classification.FieldClassificationResponse;
 import android.service.autofill.AutofillFieldClassificationService.Scores;
-import android.service.autofill.AutofillService;
 import android.service.autofill.CompositeUserData;
 import android.service.autofill.ConvertCredentialResponse;
 import android.service.autofill.Dataset;
@@ -186,7 +184,6 @@
 import android.view.autofill.IAutofillWindowPresenter;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.widget.RemoteViews;
-
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -198,7 +195,6 @@
 import com.android.server.autofill.ui.PendingUi;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -222,18 +218,21 @@
 /**
  * A session for a given activity.
  *
- * <p>This class manages the multiple {@link ViewState}s for each view it has, and keeps track
- * of the current {@link ViewState} to display the appropriate UI.
+ * <p>This class manages the multiple {@link ViewState}s for each view it has, and keeps track of
+ * the current {@link ViewState} to display the appropriate UI.
  *
- * <p>Although the autofill requests and callbacks are stateless from the service's point of
- * view, we need to keep state in the framework side for cases such as authentication. For
- * example, when service return a {@link FillResponse} that contains all the fields needed
- * to fill the activity but it requires authentication first, that response need to be held
- * until the user authenticates or it times out.
+ * <p>Although the autofill requests and callbacks are stateless from the service's point of view,
+ * we need to keep state in the framework side for cases such as authentication. For example, when
+ * service return a {@link FillResponse} that contains all the fields needed to fill the activity
+ * but it requires authentication first, that response need to be held until the user authenticates
+ * or it times out.
  */
-final class Session implements RemoteFillService.FillServiceCallbacks, ViewState.Listener,
-        AutoFillUI.AutoFillUiCallback, ValueFinder,
-        RemoteFieldClassificationService.FieldClassificationServiceCallbacks {
+final class Session
+        implements RemoteFillService.FillServiceCallbacks,
+                ViewState.Listener,
+                AutoFillUI.AutoFillUiCallback,
+                ValueFinder,
+                RemoteFieldClassificationService.FieldClassificationServiceCallbacks {
     private static final String TAG = "AutofillSession";
 
     // This should never be true in production. This is only for local debugging.
@@ -257,6 +256,7 @@
     private final AutofillManagerServiceImpl mService;
     private final Handler mHandler;
     private final AutoFillUI mUi;
+
     /**
      * Context associated with the session, it has the same {@link Context#getDisplayId() displayId}
      * of the activity being autofilled.
@@ -286,14 +286,11 @@
     /** Session is destroyed and removed from the manager service. */
     public static final int STATE_REMOVED = 3;
 
-    @IntDef(prefix = { "STATE_" }, value = {
-            STATE_UNKNOWN,
-            STATE_ACTIVE,
-            STATE_FINISHED,
-            STATE_REMOVED
-    })
+    @IntDef(
+            prefix = {"STATE_"},
+            value = {STATE_UNKNOWN, STATE_ACTIVE, STATE_FINISHED, STATE_REMOVED})
     @Retention(RetentionPolicy.SOURCE)
-    @interface SessionState{}
+    @interface SessionState {}
 
     @GuardedBy("mLock")
     private final SessionFlags mSessionFlags;
@@ -318,7 +315,8 @@
     public final int mFlags;
 
     @GuardedBy("mLock")
-    @NonNull private IBinder mActivityToken;
+    @NonNull
+    private IBinder mActivityToken;
 
     /** The app activity that's being autofilled */
     @NonNull private final ComponentName mComponentName;
@@ -341,11 +339,10 @@
      * autofill.
      */
     @GuardedBy("mLock")
-    @Nullable private Pair<Integer, InlineSuggestionsRequest> mLastInlineSuggestionsRequest;
+    @Nullable
+    private Pair<Integer, InlineSuggestionsRequest> mLastInlineSuggestionsRequest;
 
-    /**
-     * Id of the View currently being displayed.
-     */
+    /** Id of the View currently being displayed. */
     @GuardedBy("mLock")
     private @Nullable AutofillId mCurrentViewId;
 
@@ -363,8 +360,7 @@
      *
      * <p>Only {@code null} when the session is for augmented autofill only.
      */
-    @Nullable
-    private final RemoteFillService mRemoteFillService;
+    @Nullable private final RemoteFillService mRemoteFillService;
 
     /**
      * With the credman integration, Autofill Framework handles two types of autofill flows -
@@ -379,8 +375,7 @@
      * service the session was initially created with, the secondary provider handler will contain
      * the remaining autofill service.
      */
-    @Nullable
-    private final SecondaryProviderHandler mSecondaryProviderHandler;
+    @Nullable private final SecondaryProviderHandler mSecondaryProviderHandler;
 
     @GuardedBy("mLock")
     private SparseArray<FillResponse> mResponses;
@@ -395,9 +390,7 @@
     @GuardedBy("mLock")
     private ArrayList<FillContext> mContexts;
 
-    /**
-     * Whether the client has an {@link android.view.autofill.AutofillManager.AutofillCallback}.
-     */
+    /** Whether the client has an {@link android.view.autofill.AutofillManager.AutofillCallback}. */
     private boolean mHasCallback;
 
     /** Whether the session has credential manager provider as the primary provider. */
@@ -426,32 +419,24 @@
     @GuardedBy("mLock")
     private PendingUi mPendingSaveUi;
 
-    /**
-     * List of dataset ids selected by the user.
-     */
+    /** List of dataset ids selected by the user. */
     @GuardedBy("mLock")
     private ArrayList<String> mSelectedDatasetIds;
 
-    /**
-     * When the session started (using elapsed time since boot).
-     */
+    /** When the session started (using elapsed time since boot). */
     private final long mStartTime;
 
-    /**
-     * Count of FillRequests in the session.
-     */
+    /** Count of FillRequests in the session. */
     private int mRequestCount;
 
     /**
-     * Starting timestamp of latency logger.
-     * This is set when Session created or when the view is reset.
+     * Starting timestamp of latency logger. This is set when Session created or when the view is
+     * reset.
      */
     @GuardedBy("mLock")
     private long mLatencyBaseTime;
 
-    /**
-     * When the UI was shown for the first time (using elapsed time since boot).
-     */
+    /** When the UI was shown for the first time (using elapsed time since boot). */
     @GuardedBy("mLock")
     private long mUiShownTime;
 
@@ -475,15 +460,11 @@
     @GuardedBy("mLock")
     private final LocalLog mWtfHistory;
 
-    /**
-     * Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id.
-     */
+    /** Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id. */
     @GuardedBy("mLock")
     private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1);
 
-    /**
-     * Destroys the augmented Autofill UI.
-     */
+    /** Destroys the augmented Autofill UI. */
     // TODO(b/123099468): this runnable is called when the Autofill session is destroyed, the
     // main reason being the cases where user tap HOME.
     // Right now it's completely destroying the UI, but we need to decide whether / how to
@@ -494,13 +475,10 @@
     @Nullable
     private Runnable mAugmentedAutofillDestroyer;
 
-    /**
-     * List of {@link MetricsEvent#AUTOFILL_AUGMENTED_REQUEST} metrics.
-     */
+    /** List of {@link MetricsEvent#AUTOFILL_AUGMENTED_REQUEST} metrics. */
     @GuardedBy("mLock")
     private ArrayList<LogMaker> mAugmentedRequestsLogs;
 
-
     /**
      * List of autofill ids of autofillable fields present in the AssistStructure that can be used
      * to trigger new augmented autofill requests (because the "standard" service was not interested
@@ -509,23 +487,17 @@
     @GuardedBy("mLock")
     private ArrayList<AutofillId> mAugmentedAutofillableIds;
 
-    @NonNull
-    final AutofillInlineSessionController mInlineSessionController;
+    @NonNull final AutofillInlineSessionController mInlineSessionController;
 
-    /**
-     * Receiver of assist data from the app's {@link Activity}.
-     */
+    /** Receiver of assist data from the app's {@link Activity}. */
     private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
 
-    /**
-     * Receiver of assist data for pcc purpose
-     */
+    /** Receiver of assist data for pcc purpose */
     private final PccAssistDataReceiverImpl mPccAssistReceiver = new PccAssistDataReceiverImpl();
 
     private final ClassificationState mClassificationState = new ClassificationState();
 
-    @Nullable
-    private final ComponentName mCredentialAutofillService;
+    @Nullable private final ComponentName mCredentialAutofillService;
 
     // TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
     // new one per Session.
@@ -547,7 +519,10 @@
                     Slog.v(TAG, "mDelayedFillBroadcastReceiver delayed fill action received");
                     synchronized (mLock) {
                         int requestId = intent.getIntExtra(EXTRA_REQUEST_ID, 0);
-                        FillResponse response = intent.getParcelableExtra(EXTRA_FILL_RESPONSE, android.service.autofill.FillResponse.class);
+                        FillResponse response =
+                                intent.getParcelableExtra(
+                                        EXTRA_FILL_RESPONSE,
+                                        android.service.autofill.FillResponse.class);
                         mFillRequestEventLogger.maybeSetRequestTriggerReason(
                                 TRIGGER_REASON_RETRIGGER);
                         mAssistReceiver.processDelayedFillLocked(requestId, response);
@@ -575,28 +550,25 @@
     @GuardedBy("mLock")
     private SessionCommittedEventLogger mSessionCommittedEventLogger;
 
-    /**
-     * Fill dialog request would likely be sent slightly later.
-     */
+    /** Fill dialog request would likely be sent slightly later. */
     @NonNull
     @GuardedBy("mLock")
     private boolean mPreviouslyFillDialogPotentiallyStarted;
 
     /**
-     * Keeps track of if the user entered view, this is used to
-     * distinguish Fill Request that did not have user interaction
-     * with ones that did.
+     * Keeps track of if the user entered view, this is used to distinguish Fill Request that did
+     * not have user interaction with ones that did.
      *
-     * This is set to true when entering view - after FillDialog FillRequest
-     * or on plain user tap.
+     * <p>This is set to true when entering view - after FillDialog FillRequest or on plain user
+     * tap.
      */
     @NonNull
     @GuardedBy("mLock")
     private boolean mLogViewEntered;
 
     /**
-     * Keeps the fill dialog trigger ids of the last response. This invalidates
-     * the trigger ids of the previous response.
+     * Keeps the fill dialog trigger ids of the last response. This invalidates the trigger ids of
+     * the previous response.
      */
     @Nullable
     @GuardedBy("mLock")
@@ -662,9 +634,7 @@
         return false;
     }
 
-    /**
-     * Collection of flags/booleans that helps determine Session behaviors.
-     */
+    /** Collection of flags/booleans that helps determine Session behaviors. */
     private final class SessionFlags {
         /** Whether autofill is disabled by the service */
         private boolean mAutofillDisabled;
@@ -695,31 +665,35 @@
     final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
         @GuardedBy("mLock")
         private boolean mWaitForInlineRequest;
+
         @GuardedBy("mLock")
         private InlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+
         @GuardedBy("mLock")
         private FillRequest mPendingFillRequest;
+
         @GuardedBy("mLock")
         private FillRequest mLastFillRequest;
 
-        @Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(ViewState viewState,
-                boolean isInlineRequest) {
+        @Nullable
+        Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(
+                ViewState viewState, boolean isInlineRequest) {
             mPendingFillRequest = null;
             mWaitForInlineRequest = isInlineRequest;
             mPendingInlineSuggestionsRequest = null;
             if (isInlineRequest) {
                 WeakReference<AssistDataReceiverImpl> assistDataReceiverWeakReference =
-                    new WeakReference<AssistDataReceiverImpl>(this);
+                        new WeakReference<AssistDataReceiverImpl>(this);
                 WeakReference<ViewState> viewStateWeakReference =
-                    new WeakReference<ViewState>(viewState);
-                return new InlineSuggestionRequestConsumer(assistDataReceiverWeakReference,
-                    viewStateWeakReference);
+                        new WeakReference<ViewState>(viewState);
+                return new InlineSuggestionRequestConsumer(
+                        assistDataReceiverWeakReference, viewStateWeakReference);
             }
             return null;
         }
 
-        void handleInlineSuggestionRequest(InlineSuggestionsRequest inlineSuggestionsRequest,
-                ViewState viewState) {
+        void handleInlineSuggestionRequest(
+                InlineSuggestionsRequest inlineSuggestionsRequest, ViewState viewState) {
             if (sVerbose) {
                 Slog.v(TAG, "handleInlineSuggestionRequest(): inline suggestion request received");
             }
@@ -738,8 +712,10 @@
         void maybeRequestFillLocked() {
             if (mPendingFillRequest == null) {
                 if (sVerbose) {
-                        Slog.v(TAG, "maybeRequestFillLocked(): cancelling calling fill request "
-                            + "due to empty pending fill request");
+                    Slog.v(
+                            TAG,
+                            "maybeRequestFillLocked(): cancelling calling fill request "
+                                    + "due to empty pending fill request");
                 }
                 return;
             }
@@ -748,27 +724,35 @@
             if (mWaitForInlineRequest) {
                 if (mPendingInlineSuggestionsRequest == null) {
                     if (sVerbose) {
-                        Slog.v(TAG, "maybeRequestFillLocked(): cancelling calling fill request "
-                            + "due to waiting for inline request and pending inline request is "
-                            + "currently empty");
+                        Slog.v(
+                                TAG,
+                                "maybeRequestFillLocked(): cancelling calling fill request due to"
+                                    + " waiting for inline request and pending inline request is"
+                                    + " currently empty");
                     }
                     return;
                 }
                 if (sVerbose) {
-                    Slog.v(TAG, "maybeRequestFillLocked(): adding inline request to pending "
-                        + "fill request");
+                    Slog.v(
+                            TAG,
+                            "maybeRequestFillLocked(): adding inline request to pending "
+                                    + "fill request");
                 }
-                mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
-                        mPendingFillRequest.getFillContexts(),
-                        mPendingFillRequest.getHints(),
-                        mPendingFillRequest.getClientState(),
-                        mPendingFillRequest.getFlags(),
-                        mPendingInlineSuggestionsRequest,
-                        mPendingFillRequest.getDelayedFillIntentSender());
+                mPendingFillRequest =
+                        new FillRequest(
+                                mPendingFillRequest.getId(),
+                                mPendingFillRequest.getFillContexts(),
+                                mPendingFillRequest.getHints(),
+                                mPendingFillRequest.getClientState(),
+                                mPendingFillRequest.getFlags(),
+                                mPendingInlineSuggestionsRequest,
+                                mPendingFillRequest.getDelayedFillIntentSender());
             } else {
                 if (sVerbose) {
-                    Slog.v(TAG, "maybeRequestFillLocked(): not adding inline request to pending "
-                        + "fill request");
+                    Slog.v(
+                            TAG,
+                            "maybeRequestFillLocked(): not adding inline request to pending "
+                                    + "fill request");
                 }
             }
 
@@ -780,19 +764,19 @@
                     && mSecondaryProviderHandler != null) {
                 Slog.v(TAG, "Requesting fill response to secondary provider.");
                 if (!mIsPrimaryCredential) {
-                    mPendingFillRequest = addCredentialManagerDataToClientState(
-                            mPendingFillRequest,
-                            mPendingInlineSuggestionsRequest, id);
+                    mPendingFillRequest =
+                            addCredentialManagerDataToClientState(
+                                    mPendingFillRequest, mPendingInlineSuggestionsRequest, id);
                 }
-                mSecondaryProviderHandler.onFillRequest(mPendingFillRequest,
-                        mPendingFillRequest.getFlags(), mClient.asBinder());
+                mSecondaryProviderHandler.onFillRequest(
+                        mPendingFillRequest, mPendingFillRequest.getFlags(), mClient.asBinder());
             } else if (mRemoteFillService != null) {
                 if (mIsPrimaryCredential) {
-                    mPendingFillRequest = addCredentialManagerDataToClientState(
-                            mPendingFillRequest,
-                            mPendingInlineSuggestionsRequest, id);
-                    mRemoteFillService.onFillCredentialRequest(mPendingFillRequest,
-                            mClient.asBinder());
+                    mPendingFillRequest =
+                            addCredentialManagerDataToClientState(
+                                    mPendingFillRequest, mPendingInlineSuggestionsRequest, id);
+                    mRemoteFillService.onFillCredentialRequest(
+                            mPendingFillRequest, mClient.asBinder());
                 } else {
                     mRemoteFillService.onFillRequest(mPendingFillRequest);
                 }
@@ -813,8 +797,11 @@
         @Override
         public void onHandleAssistData(Bundle resultData) throws RemoteException {
             if (mRemoteFillService == null) {
-                wtf(null, "onHandleAssistData() called without a remote service. "
-                        + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+                wtf(
+                        null,
+                        "onHandleAssistData() called without a remote service. "
+                                + "mForAugmentedAutofillOnly: %s",
+                        mSessionFlags.mAugmentedAutofillOnly);
                 return;
             }
             // Keeps to prevent it is cleared on multiple threads.
@@ -824,7 +811,9 @@
                 return;
             }
 
-            final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
+            final AssistStructure structure =
+                    resultData.getParcelable(
+                            ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
             if (structure == null) {
                 Slog.e(TAG, "No assist structure - app might have crashed providing it");
                 return;
@@ -852,13 +841,16 @@
                 try {
                     structure.ensureDataForAutofill();
                 } catch (RuntimeException e) {
-                    wtf(e, "Exception lazy loading assist structure for %s: %s",
-                            structure.getActivityComponent(), e);
+                    wtf(
+                            e,
+                            "Exception lazy loading assist structure for %s: %s",
+                            structure.getActivityComponent(),
+                            e);
                     return;
                 }
 
-                final ArrayList<AutofillId> ids = Helper.getAutofillIds(structure,
-                        /* autofillableOnly= */false);
+                final ArrayList<AutofillId> ids =
+                        Helper.getAutofillIds(structure, /* autofillableOnly= */ false);
                 for (int i = 0; i < ids.size(); i++) {
                     ids.get(i).setSessionId(Session.this.id);
                 }
@@ -868,8 +860,9 @@
 
                 if (mCompatMode) {
                     // Sanitize URL bar, if needed
-                    final String[] urlBarIds = mService.getUrlBarResourceIdsForCompatMode(
-                            mComponentName.getPackageName());
+                    final String[] urlBarIds =
+                            mService.getUrlBarResourceIdsForCompatMode(
+                                    mComponentName.getPackageName());
                     if (sDebug) {
                         Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
                     }
@@ -878,11 +871,19 @@
                         if (mUrlBar != null) {
                             final AutofillId urlBarId = mUrlBar.getAutofillId();
                             if (sDebug) {
-                                Slog.d(TAG, "Setting urlBar as id=" + urlBarId + " and domain "
-                                        + mUrlBar.getWebDomain());
+                                Slog.d(
+                                        TAG,
+                                        "Setting urlBar as id="
+                                                + urlBarId
+                                                + " and domain "
+                                                + mUrlBar.getWebDomain());
                             }
-                            final ViewState viewState = new ViewState(urlBarId, Session.this,
-                                    ViewState.STATE_URL_BAR, mIsPrimaryCredential);
+                            final ViewState viewState =
+                                    new ViewState(
+                                            urlBarId,
+                                            Session.this,
+                                            ViewState.STATE_URL_BAR,
+                                            mIsPrimaryCredential);
                             mViewStates.put(urlBarId, viewState);
                         }
                     }
@@ -907,11 +908,17 @@
                 final List<String> hints = getTypeHintsForProvider();
 
                 mDelayedFillPendingIntent = createPendingIntent(requestId);
-                request = new FillRequest(requestId, contexts, hints, mClientState, flags,
-                        /*inlineSuggestionsRequest=*/ null,
-                        /*delayedFillIntentSender=*/ mDelayedFillPendingIntent == null
-                            ? null
-                            : mDelayedFillPendingIntent.getIntentSender());
+                request =
+                        new FillRequest(
+                                requestId,
+                                contexts,
+                                hints,
+                                mClientState,
+                                flags,
+                                /* inlineSuggestionsRequest= */ null,
+                                /* delayedFillIntentSender= */ mDelayedFillPendingIntent == null
+                                        ? null
+                                        : mDelayedFillPendingIntent.getIntentSender());
 
                 mPendingFillRequest = request;
                 maybeRequestFillLocked();
@@ -930,39 +937,49 @@
         @GuardedBy("mLock")
         void processDelayedFillLocked(int requestId, FillResponse response) {
             if (mLastFillRequest != null && requestId == mLastFillRequest.getId()) {
-                Slog.v(TAG, "processDelayedFillLocked: "
-                        + "calling onFillRequestSuccess with new response");
-                onFillRequestSuccess(requestId, response,
-                        mService.getServicePackageName(), mLastFillRequest.getFlags());
+                Slog.v(
+                        TAG,
+                        "processDelayedFillLocked: "
+                                + "calling onFillRequestSuccess with new response");
+                onFillRequestSuccess(
+                        requestId,
+                        response,
+                        mService.getServicePackageName(),
+                        mLastFillRequest.getFlags());
             }
         }
     }
 
-    private FillRequest addCredentialManagerDataToClientState(FillRequest pendingFillRequest,
-            InlineSuggestionsRequest pendingInlineSuggestionsRequest, int sessionId) {
+    private FillRequest addCredentialManagerDataToClientState(
+            FillRequest pendingFillRequest,
+            InlineSuggestionsRequest pendingInlineSuggestionsRequest,
+            int sessionId) {
 
         if (pendingFillRequest.getClientState() == null) {
-            pendingFillRequest = new FillRequest(pendingFillRequest.getId(),
-                    pendingFillRequest.getFillContexts(),
-                    pendingFillRequest.getHints(),
-                    new Bundle(),
-                    pendingFillRequest.getFlags(),
-                    pendingInlineSuggestionsRequest,
-                    pendingFillRequest.getDelayedFillIntentSender());
+            pendingFillRequest =
+                    new FillRequest(
+                            pendingFillRequest.getId(),
+                            pendingFillRequest.getFillContexts(),
+                            pendingFillRequest.getHints(),
+                            new Bundle(),
+                            pendingFillRequest.getFlags(),
+                            pendingInlineSuggestionsRequest,
+                            pendingFillRequest.getDelayedFillIntentSender());
         }
         pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, sessionId);
         pendingFillRequest.getClientState().putInt(REQUEST_ID_KEY, pendingFillRequest.getId());
-        ResultReceiver resultReceiver = constructCredentialManagerCallback(
-                pendingFillRequest.getId());
-        pendingFillRequest.getClientState().putParcelable(
-                CredentialManager.EXTRA_AUTOFILL_RESULT_RECEIVER, resultReceiver);
+        ResultReceiver resultReceiver =
+                constructCredentialManagerCallback(pendingFillRequest.getId());
+        pendingFillRequest
+                .getClientState()
+                .putParcelable(CredentialManager.EXTRA_AUTOFILL_RESULT_RECEIVER, resultReceiver);
         return pendingFillRequest;
     }
 
     /**
-     * Get the list of valid autofill hint types from Device flags
-     * Returns empty list if PCC is off or no types available
-    */
+     * Get the list of valid autofill hint types from Device flags Returns empty list if PCC is off
+     * or no types available
+     */
     private List<String> getTypeHintsForProvider() {
         if (!mService.isPccClassificationEnabled()) {
             return Collections.EMPTY_LIST;
@@ -978,9 +995,7 @@
         return List.of(typeHints.split(PCC_HINTS_DELIMITER));
     }
 
-    /**
-     * Assist Data Receiver for PCC
-     */
+    /** Assist Data Receiver for PCC */
     private final class PccAssistDataReceiverImpl extends IAssistDataReceiver.Stub {
 
         @GuardedBy("mLock")
@@ -998,7 +1013,7 @@
                                 new WeakReference<>(Session.this);
                 remoteFieldClassificationService.onFieldClassificationRequest(
                         mClassificationState.mPendingFieldClassificationRequest,
-                                fieldClassificationServiceCallbacksWeakRef);
+                        fieldClassificationServiceCallbacksWeakRef);
             }
             mClassificationState.onFieldClassificationRequestSent();
         }
@@ -1006,26 +1021,35 @@
         @Override
         public void onHandleAssistData(Bundle resultData) throws RemoteException {
             // TODO: add a check if pcc field classification service is present
-            final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE,
-                android.app.assist.AssistStructure.class);
+            final AssistStructure structure =
+                    resultData.getParcelable(
+                            ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
             if (structure == null) {
-                Slog.e(TAG, "No assist structure for pcc detection - "
-                    + "app might have crashed providing it");
+                Slog.e(
+                        TAG,
+                        "No assist structure for pcc detection - "
+                                + "app might have crashed providing it");
                 return;
             }
 
             final Bundle receiverExtras = resultData.getBundle(ASSIST_KEY_RECEIVER_EXTRAS);
             if (receiverExtras == null) {
-                Slog.e(TAG, "No receiver extras for pcc detection - "
-                    + "app might have crashed providing it");
+                Slog.e(
+                        TAG,
+                        "No receiver extras for pcc detection - "
+                                + "app might have crashed providing it");
                 return;
             }
 
             final int requestId = receiverExtras.getInt(EXTRA_REQUEST_ID);
 
             if (sVerbose) {
-                Slog.v(TAG, "New structure for PCC Detection: requestId " + requestId + ": "
-                        + structure);
+                Slog.v(
+                        TAG,
+                        "New structure for PCC Detection: requestId "
+                                + requestId
+                                + ": "
+                                + structure);
             }
 
             synchronized (mLock) {
@@ -1037,13 +1061,16 @@
                 try {
                     structure.ensureDataForAutofill();
                 } catch (RuntimeException e) {
-                    wtf(e, "Exception lazy loading assist structure for %s: %s",
-                        structure.getActivityComponent(), e);
+                    wtf(
+                            e,
+                            "Exception lazy loading assist structure for %s: %s",
+                            structure.getActivityComponent(),
+                            e);
                     return;
                 }
 
-                final ArrayList<AutofillId> ids = Helper.getAutofillIds(structure,
-                    /* autofillableOnly= */false);
+                final ArrayList<AutofillId> ids =
+                        Helper.getAutofillIds(structure, /* autofillableOnly= */ false);
                 for (int i = 0; i < ids.size(); i++) {
                     ids.get(i).setSessionId(Session.this.id);
                 }
@@ -1066,13 +1093,18 @@
         PendingIntent pendingIntent;
         final long identity = Binder.clearCallingIdentity();
         try {
-            Intent intent = new Intent(ACTION_DELAYED_FILL).setPackage("android")
-                    .putExtra(EXTRA_REQUEST_ID, requestId);
-            pendingIntent = PendingIntent.getBroadcast(
-                    mContext, this.id, intent,
-                    PendingIntent.FLAG_MUTABLE
-                        | PendingIntent.FLAG_ONE_SHOT
-                        | PendingIntent.FLAG_CANCEL_CURRENT);
+            Intent intent =
+                    new Intent(ACTION_DELAYED_FILL)
+                            .setPackage("android")
+                            .putExtra(EXTRA_REQUEST_ID, requestId);
+            pendingIntent =
+                    PendingIntent.getBroadcast(
+                            mContext,
+                            this.id,
+                            intent,
+                            PendingIntent.FLAG_MUTABLE
+                                    | PendingIntent.FLAG_ONE_SHOT
+                                    | PendingIntent.FLAG_CANCEL_CURRENT);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -1113,9 +1145,7 @@
         }
     }
 
-    /**
-     * Returns the ids of all entries in {@link #mViewStates} in the same order.
-     */
+    /** Returns the ids of all entries in {@link #mViewStates} in the same order. */
     @GuardedBy("mLock")
     private AutofillId[] getIdsOfAllViewStatesLocked() {
         final int numViewState = mViewStates.size();
@@ -1164,8 +1194,8 @@
     }
 
     /**
-     * <p>Gets the value of a field, using either the {@code viewStates} or the {@code mContexts},
-     * or {@code null} when not found on either of them.
+     * Gets the value of a field, using either the {@code viewStates} or the {@code mContexts}, or
+     * {@code null} when not found on either of them.
      */
     @GuardedBy("mLock")
     @Nullable
@@ -1180,16 +1210,22 @@
         final ArrayList<Session> previousSessions = mService.getPreviousSessionsLocked(this);
         if (previousSessions != null) {
             if (sDebug) {
-                Slog.d(TAG, "findValueLocked(): looking on " + previousSessions.size()
-                        + " previous sessions for autofillId " + autofillId);
+                Slog.d(
+                        TAG,
+                        "findValueLocked(): looking on "
+                                + previousSessions.size()
+                                + " previous sessions for autofillId "
+                                + autofillId);
             }
             for (int i = 0; i < previousSessions.size(); i++) {
                 final Session previousSession = previousSessions.get(i);
-                final AutofillValue previousValue = previousSession
-                        .findValueFromThisSessionOnlyLocked(autofillId);
+                final AutofillValue previousValue =
+                        previousSession.findValueFromThisSessionOnlyLocked(autofillId);
                 if (previousValue != null) {
-                    return getSanitizedValue(createSanitizers(previousSession.getSaveInfoLocked()),
-                            autofillId, previousValue);
+                    return getSanitizedValue(
+                            createSanitizers(previousSession.getSaveInfoLocked()),
+                            autofillId,
+                            previousValue);
                 }
             }
         }
@@ -1212,16 +1248,22 @@
             AutofillValue candidateSaveValue = state.getCandidateSaveValue();
             if (candidateSaveValue != null && !candidateSaveValue.isEmpty()) {
                 if (sDebug) {
-                    Slog.d(TAG, "findValueLocked(): current value for " + autofillId
-                            + " is empty, using candidateSaveValue instead.");
+                    Slog.d(
+                            TAG,
+                            "findValueLocked(): current value for "
+                                    + autofillId
+                                    + " is empty, using candidateSaveValue instead.");
                 }
                 return candidateSaveValue;
             }
         }
         if (value == null) {
             if (sDebug) {
-                Slog.d(TAG, "findValueLocked(): no current value for " + autofillId
-                        + ", checking value from previous fill contexts");
+                Slog.d(
+                        TAG,
+                        "findValueLocked(): no current value for "
+                                + autofillId
+                                + ", checking value from previous fill contexts");
                 value = getValueFromContextsLocked(autofillId);
             }
         }
@@ -1231,17 +1273,16 @@
     /**
      * Updates values of the nodes in the context's structure so that:
      *
-     * - proper node is focused
-     * - autofillValue is sent back to service when it was previously autofilled
-     * - autofillValue is sent in the view used to force a request
+     * <p>- proper node is focused - autofillValue is sent back to service when it was previously
+     * autofilled - autofillValue is sent in the view used to force a request
      *
      * @param fillContext The context to be filled
      * @param flags The flags that started the session
      */
     @GuardedBy("mLock")
     private void fillContextWithAllowedValuesLocked(@NonNull FillContext fillContext, int flags) {
-        final ViewNode[] nodes = fillContext
-                .findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
+        final ViewNode[] nodes =
+                fillContext.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
 
         final int numViewState = mViewStates.size();
         for (int i = 0; i < numViewState; i++) {
@@ -1250,7 +1291,8 @@
             final ViewNode node = nodes[i];
             if (node == null) {
                 if (sVerbose) {
-                    Slog.v(TAG,
+                    Slog.v(
+                            TAG,
                             "fillContextWithAllowedValuesLocked(): no node for " + viewState.id);
                 }
                 continue;
@@ -1277,14 +1319,15 @@
         }
     }
 
-    /**
-     * Cancels the last request sent to the {@link #mRemoteFillService}.
-     */
+    /** Cancels the last request sent to the {@link #mRemoteFillService}. */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
         if (mRemoteFillService == null) {
-            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+            wtf(
+                    null,
+                    "cancelCurrentRequestLocked() called without a remote service. "
+                            + "mForAugmentedAutofillOnly: %s",
+                    mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
         final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
@@ -1318,21 +1361,20 @@
     private Optional<Integer> requestNewFillResponseLocked(
             @NonNull ViewState viewState, int newState, int flags) {
         boolean isSecondary = shouldRequestSecondaryProvider(flags);
-        final FillResponse existingResponse = isSecondary
-                ? viewState.getSecondaryResponse() : viewState.getResponse();
+        final FillResponse existingResponse =
+                isSecondary ? viewState.getSecondaryResponse() : viewState.getResponse();
         mFillRequestEventLogger.startLogForNewRequest();
         mRequestCount++;
         mFillRequestEventLogger.maybeSetAppPackageUid(uid);
         mFillRequestEventLogger.maybeSetFlags(mFlags);
-        if(mPreviouslyFillDialogPotentiallyStarted) {
+        if (mPreviouslyFillDialogPotentiallyStarted) {
             mFillRequestEventLogger.maybeSetRequestTriggerReason(TRIGGER_REASON_PRE_TRIGGER);
         } else {
             if ((flags & FLAG_MANUAL_REQUEST) != 0) {
                 mFillRequestEventLogger.maybeSetRequestTriggerReason(
                         TRIGGER_REASON_EXPLICITLY_REQUESTED);
             } else {
-                mFillRequestEventLogger.maybeSetRequestTriggerReason(
-                        TRIGGER_REASON_NORMAL_TRIGGER);
+                mFillRequestEventLogger.maybeSetRequestTriggerReason(TRIGGER_REASON_NORMAL_TRIGGER);
             }
         }
         if (existingResponse != null) {
@@ -1348,9 +1390,14 @@
         mSessionState = STATE_ACTIVE;
         if (mSessionFlags.mAugmentedAutofillOnly || mRemoteFillService == null) {
             if (sVerbose) {
-                Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead "
-                        + "(mForAugmentedAutofillOnly=" + mSessionFlags.mAugmentedAutofillOnly
-                        + ", flags=" + flags + ")");
+                Slog.v(
+                        TAG,
+                        "requestNewFillResponse(): triggering augmented autofill instead "
+                                + "(mForAugmentedAutofillOnly="
+                                + mSessionFlags.mAugmentedAutofillOnly
+                                + ", flags="
+                                + flags
+                                + ")");
             }
             mSessionFlags.mAugmentedAutofillOnly = true;
             mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID);
@@ -1365,16 +1412,23 @@
 
         // Create a metrics log for the request
         final int ordinal = mRequestLogs.size() + 1;
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
+        final LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
         if (flags != 0) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags);
         }
         mRequestLogs.put(requestId, log);
 
         if (sVerbose) {
-            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId
-                    + ", flags=" + flags);
+            Slog.v(
+                    TAG,
+                    "Requesting structure for request #"
+                            + ordinal
+                            + " ,requestId="
+                            + requestId
+                            + ", flags="
+                            + flags);
         }
         boolean isCredmanRequested = (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0;
         mFillRequestEventLogger.maybeSetRequestId(requestId);
@@ -1406,11 +1460,12 @@
         // is also not focused.
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if (mSessionFlags.mInlineSupportedByService && remoteRenderService != null
-            && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
+        if (mSessionFlags.mInlineSupportedByService
+                && remoteRenderService != null
+                && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
             Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
-                mAssistReceiver.newAutofillRequestLocked(viewState,
-                    /* isInlineRequest= */ true);
+                    mAssistReceiver.newAutofillRequestLocked(
+                            viewState, /* isInlineRequest= */ true);
             if (inlineSuggestionsRequestConsumer != null) {
                 final int requestIdCopy = requestId;
                 final AutofillId focusedId = mCurrentViewId;
@@ -1423,8 +1478,9 @@
                                         requestIdCopy,
                                         inlineSuggestionsRequestConsumer,
                                         focusedId);
-                RemoteCallback inlineSuggestionRendorInfoCallback = new RemoteCallback(
-                        inlineSuggestionRendorInfoCallbackOnResultListener, mHandler);
+                RemoteCallback inlineSuggestionRendorInfoCallback =
+                        new RemoteCallback(
+                                inlineSuggestionRendorInfoCallbackOnResultListener, mHandler);
 
                 remoteRenderService.getInlineSuggestionsRendererInfo(
                         inlineSuggestionRendorInfoCallback);
@@ -1465,8 +1521,9 @@
             receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
             final long identity = Binder.clearCallingIdentity();
             try {
-                if (!ActivityTaskManager.getService().requestAutofillData(mPccAssistReceiver,
-                        receiverExtras, mActivityToken, flags)) {
+                if (!ActivityTaskManager.getService()
+                        .requestAutofillData(
+                                mPccAssistReceiver, receiverExtras, mActivityToken, flags)) {
                     Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
                 }
             } finally {
@@ -1483,8 +1540,9 @@
             receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
             final long identity = Binder.clearCallingIdentity();
             try {
-                if (!ActivityTaskManager.getService().requestAutofillData(mAssistReceiver,
-                        receiverExtras, mActivityToken, flags)) {
+                if (!ActivityTaskManager.getService()
+                        .requestAutofillData(
+                                mAssistReceiver, receiverExtras, mActivityToken, flags)) {
                     Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
                 }
             } finally {
@@ -1495,13 +1553,27 @@
         }
     }
 
-    Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
-            @NonNull Context context, @NonNull Handler handler, int userId, @NonNull Object lock,
-            int sessionId, int taskId, int uid, @NonNull IBinder activityToken,
-            @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
-            @NonNull LocalLog wtfHistory, @Nullable ComponentName serviceComponentName,
-            @NonNull ComponentName componentName, boolean compatMode,
-            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags,
+    Session(
+            @NonNull AutofillManagerServiceImpl service,
+            @NonNull AutoFillUI ui,
+            @NonNull Context context,
+            @NonNull Handler handler,
+            int userId,
+            @NonNull Object lock,
+            int sessionId,
+            int taskId,
+            int uid,
+            @NonNull IBinder activityToken,
+            @NonNull IBinder client,
+            boolean hasCallback,
+            @NonNull LocalLog uiLatencyHistory,
+            @NonNull LocalLog wtfHistory,
+            @Nullable ComponentName serviceComponentName,
+            @NonNull ComponentName componentName,
+            boolean compatMode,
+            boolean bindInstantServiceAllowed,
+            boolean forAugmentedAutofillOnly,
+            int flags,
             @NonNull InputMethodManagerInternal inputMethodManagerInternal,
             boolean isPrimaryCredential) {
         if (sessionId < 0) {
@@ -1533,22 +1605,40 @@
             primaryServiceComponentName = serviceComponentName;
             secondaryServiceComponentName = mCredentialAutofillService;
         }
-        Slog.v(TAG, "Primary service component name: " + primaryServiceComponentName
-                + ", secondary service component name: " + secondaryServiceComponentName);
+        Slog.v(
+                TAG,
+                "Primary service component name: "
+                        + primaryServiceComponentName
+                        + ", secondary service component name: "
+                        + secondaryServiceComponentName);
 
-        mRemoteFillService = primaryServiceComponentName == null ? null
-                : new RemoteFillService(context, primaryServiceComponentName, userId, this,
-                        bindInstantServiceAllowed, mCredentialAutofillService);
-        mSecondaryProviderHandler = secondaryServiceComponentName == null ? null
-                : new SecondaryProviderHandler(context, userId, bindInstantServiceAllowed,
-                this::onSecondaryFillResponse, secondaryServiceComponentName,
-                        mCredentialAutofillService);
+        mRemoteFillService =
+                primaryServiceComponentName == null
+                        ? null
+                        : new RemoteFillService(
+                                context,
+                                primaryServiceComponentName,
+                                userId,
+                                this,
+                                bindInstantServiceAllowed,
+                                mCredentialAutofillService);
+        mSecondaryProviderHandler =
+                secondaryServiceComponentName == null
+                        ? null
+                        : new SecondaryProviderHandler(
+                                context,
+                                userId,
+                                bindInstantServiceAllowed,
+                                this::onSecondaryFillResponse,
+                                secondaryServiceComponentName,
+                                mCredentialAutofillService);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
-        int displayId = LocalServices.getService(ActivityTaskManagerInternal.class)
-                .getDisplayId(activityToken);
+        int displayId =
+                LocalServices.getService(ActivityTaskManagerInternal.class)
+                        .getDisplayId(activityToken);
         mContext = Helper.getDisplayContext(context, displayId);
         mComponentName = componentName;
         mCompatMode = compatMode;
@@ -1557,8 +1647,9 @@
         mStartTime = SystemClock.elapsedRealtime();
         mLatencyBaseTime = mStartTime;
         mRequestCount = 0;
-        mPresentationStatsEventLogger = PresentationStatsEventLogger.createPresentationLog(
-                sessionId, uid, mLatencyBaseTime);
+        mPresentationStatsEventLogger =
+                PresentationStatsEventLogger.createPresentationLog(
+                        sessionId, uid, mLatencyBaseTime);
         mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId);
         mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId);
         mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId);
@@ -1574,33 +1665,39 @@
             setClientLocked(client);
         }
 
-        mInlineSessionController = new AutofillInlineSessionController(inputMethodManagerInternal,
-                userId, componentName, handler, mLock,
-                new InlineFillUi.InlineUiEventCallback() {
-                    @Override
-                    public void notifyInlineUiShown(AutofillId autofillId) {
-                        notifyFillUiShown(autofillId);
-                    }
+        mInlineSessionController =
+                new AutofillInlineSessionController(
+                        inputMethodManagerInternal,
+                        userId,
+                        componentName,
+                        handler,
+                        mLock,
+                        new InlineFillUi.InlineUiEventCallback() {
+                            @Override
+                            public void notifyInlineUiShown(AutofillId autofillId) {
+                                notifyFillUiShown(autofillId);
+                            }
 
-                    @Override
-                    public void notifyInlineUiHidden(AutofillId autofillId) {
-                        notifyFillUiHidden(autofillId);
-                    }
-                });
+                            @Override
+                            public void notifyInlineUiHidden(AutofillId autofillId) {
+                                notifyFillUiHidden(autofillId);
+                            }
+                        });
 
-        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
+        mMetricsLogger.write(
+                newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
         mLogViewEntered = false;
     }
 
     private ComponentName getCredentialAutofillService(Context context) {
         ComponentName componentName = null;
-        String credentialManagerAutofillCompName = context.getResources().getString(
-                R.string.config_defaultCredentialManagerAutofillService);
+        String credentialManagerAutofillCompName =
+                context.getResources()
+                        .getString(R.string.config_defaultCredentialManagerAutofillService);
         if (credentialManagerAutofillCompName != null
                 && !credentialManagerAutofillCompName.isEmpty()) {
-            componentName = ComponentName.unflattenFromString(
-                    credentialManagerAutofillCompName);
+            componentName = ComponentName.unflattenFromString(credentialManagerAutofillCompName);
         }
         if (componentName == null) {
             Slog.w(TAG, "Invalid CredentialAutofillService");
@@ -1614,7 +1711,8 @@
      * @return The activity token
      */
     @GuardedBy("mLock")
-    @NonNull IBinder getActivityTokenLocked() {
+    @NonNull
+    IBinder getActivityTokenLocked() {
         return mActivityToken;
     }
 
@@ -1627,8 +1725,11 @@
     void switchActivity(@NonNull IBinder newActivity, @NonNull IBinder newClient) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#switchActivity() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#switchActivity() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             mActivityToken = newActivity;
@@ -1643,17 +1744,22 @@
     private void setClientLocked(@NonNull IBinder client) {
         unlinkClientVultureLocked();
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
-        mClientVulture = () -> {
-            synchronized (mLock) {
-                Slog.d(TAG, "handling death of " + mActivityToken + " when saving="
-                        + mSessionFlags.mShowingSaveUi);
-                if (mSessionFlags.mShowingSaveUi) {
-                    mUi.hideFillUi(this);
-                } else {
-                    mUi.destroyAll(mPendingSaveUi, this, false);
-                }
-            }
-        };
+        mClientVulture =
+                () -> {
+                    synchronized (mLock) {
+                        Slog.d(
+                                TAG,
+                                "handling death of "
+                                        + mActivityToken
+                                        + " when saving="
+                                        + mSessionFlags.mShowingSaveUi);
+                        if (mSessionFlags.mShowingSaveUi) {
+                            mUi.hideFillUi(this);
+                        } else {
+                            mUi.destroyAll(mPendingSaveUi, this, false);
+                        }
+                    }
+                };
         try {
             mClient.asBinder().linkToDeath(mClientVulture, 0);
         } catch (RemoteException e) {
@@ -1676,8 +1782,11 @@
     // FillServiceCallbacks
     @Override
     @SuppressWarnings("GuardedBy")
-    public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
-            @NonNull String servicePackageName, int requestFlags) {
+    public void onFillRequestSuccess(
+            int requestId,
+            @Nullable FillResponse response,
+            @NonNull String servicePackageName,
+            int requestFlags) {
         final AutofillId[] fieldClassificationIds;
 
         final LogMaker requestLog;
@@ -1701,8 +1810,11 @@
                     getDetectionPreferenceForLogging());
 
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillRequestSuccess() rejected - session: "
+                                + id
+                                + " destroyed");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
                 return;
@@ -1713,8 +1825,11 @@
                 // saveUi gets closed, the session will be destroyed and AutofillManager will reset
                 // its state. Processing the fill request will result in a great chance of corrupt
                 // state in Autofill.
-                Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
-                        + id + " is showing saveUi");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillRequestSuccess() rejected - session: "
+                                + id
+                                + " is showing saveUi");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
                 return;
@@ -1760,22 +1875,21 @@
             }
         }
 
-
         final long disableDuration = response.getDisableDuration();
         final boolean autofillDisabled = disableDuration > 0;
         if (autofillDisabled) {
             final int flags = response.getFlags();
             final boolean disableActivityOnly =
                     (flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0;
-            notifyDisableAutofillToClient(disableDuration,
-                    disableActivityOnly ? mComponentName : null);
+            notifyDisableAutofillToClient(
+                    disableDuration, disableActivityOnly ? mComponentName : null);
 
             if (disableActivityOnly) {
-                mService.disableAutofillForActivity(mComponentName, disableDuration,
-                        id, mCompatMode);
+                mService.disableAutofillForActivity(
+                        mComponentName, disableDuration, id, mCompatMode);
             } else {
-                mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
-                        id, mCompatMode);
+                mService.disableAutofillForApp(
+                        mComponentName.getPackageName(), disableDuration, id, mCompatMode);
             }
 
             synchronized (mLock) {
@@ -1786,17 +1900,22 @@
                 if (triggerAugmentedAutofillLocked(requestFlags) != null) {
                     mSessionFlags.mAugmentedAutofillOnly = true;
                     if (sDebug) {
-                        Slog.d(TAG, "Service disabled autofill for " + mComponentName
-                                + ", but session is kept for augmented autofill only");
+                        Slog.d(
+                                TAG,
+                                "Service disabled autofill for "
+                                        + mComponentName
+                                        + ", but session is kept for augmented autofill only");
                     }
                     return;
                 }
             }
 
             if (sDebug) {
-                final StringBuilder message = new StringBuilder("Service disabled autofill for ")
+                final StringBuilder message =
+                        new StringBuilder("Service disabled autofill for ")
                                 .append(mComponentName)
-                                .append(": flags=").append(flags)
+                                .append(": flags=")
+                                .append(flags)
                                 .append(", duration=");
                 TimeUtils.formatDuration(disableDuration, message);
                 Slog.d(TAG, message.toString());
@@ -1816,8 +1935,9 @@
         }
 
         if (requestLog != null) {
-            requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
-                            response.getDatasets() == null ? 0 : response.getDatasets().size());
+            requestLog.addTaggedData(
+                    MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                    response.getDatasets() == null ? 0 : response.getDatasets().size());
             if (fieldClassificationIds != null) {
                 requestLog.addTaggedData(
                         MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
@@ -1840,10 +1960,9 @@
         }
     }
 
-
     @GuardedBy("mLock")
-    private void processResponseLockedForPcc(@NonNull FillResponse response,
-            @Nullable Bundle newClientState, int flags) {
+    private void processResponseLockedForPcc(
+            @NonNull FillResponse response, @Nullable Bundle newClientState, int flags) {
         if (DBG) {
             Slog.d(TAG, "DBG: Initial response: " + response);
         }
@@ -1851,9 +1970,7 @@
             response = getEffectiveFillResponse(response);
             if (isEmptyResponse(response)) {
                 // Treat it as a null response.
-                processNullResponseLocked(
-                        response != null ? response.getRequestId() : 0,
-                        flags);
+                processNullResponseLocked(response != null ? response.getRequestId() : 0, flags);
                 return;
             }
             if (DBG) {
@@ -1870,9 +1987,9 @@
             return ((response.getDatasets() == null || response.getDatasets().isEmpty())
                     && response.getAuthentication() == null
                     && (saveInfo == null
-                        || (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
-                            && ArrayUtils.isEmpty(saveInfo.getRequiredIds())
-                            && ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
+                            || (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
+                                    && ArrayUtils.isEmpty(saveInfo.getRequiredIds())
+                                    && ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
                     && (ArrayUtils.isEmpty(response.getFieldClassificationIds())));
         }
     }
@@ -1884,10 +2001,12 @@
         computeDatasetsForProviderAndUpdateContainer(response, autofillProviderContainer);
 
         if (DBG) {
-            Slog.d(TAG, "DBG: computeDatasetsForProviderAndUpdateContainer: "
-                    + autofillProviderContainer);
+            Slog.d(
+                    TAG,
+                    "DBG: computeDatasetsForProviderAndUpdateContainer: "
+                            + autofillProviderContainer);
         }
-        if (!mService.isPccClassificationEnabled())  {
+        if (!mService.isPccClassificationEnabled()) {
             if (sVerbose) {
                 Slog.v(TAG, "PCC classification is disabled");
             }
@@ -1897,10 +2016,14 @@
             if (mClassificationState.mState != ClassificationState.STATE_RESPONSE
                     || mClassificationState.mLastFieldClassificationResponse == null) {
                 if (sVerbose) {
-                    Slog.v(TAG, "PCC classification no last response:"
-                            + (mClassificationState.mLastFieldClassificationResponse == null)
-                            +   " ,ineligible state="
-                            + (mClassificationState.mState != ClassificationState.STATE_RESPONSE));
+                    Slog.v(
+                            TAG,
+                            "PCC classification no last response:"
+                                    + (mClassificationState.mLastFieldClassificationResponse
+                                            == null)
+                                    + " ,ineligible state="
+                                    + (mClassificationState.mState
+                                            != ClassificationState.STATE_RESPONSE));
                 }
                 return createShallowCopy(response, autofillProviderContainer);
             }
@@ -1966,8 +2089,11 @@
             mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
                     (int) (fillRequestReceivedRelativeTimestamp));
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onSecondaryFillResponse() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onSecondaryFillResponse() rejected - session: "
+                                + id
+                                + " destroyed");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
                 return;
@@ -1981,7 +2107,10 @@
                 mSecondaryResponses = new SparseArray<>(2);
             }
             mSecondaryResponses.put(fillResponse.getRequestId(), fillResponse);
-            setViewStatesLocked(fillResponse, ViewState.STATE_FILLABLE, /* clearResponse= */ false,
+            setViewStatesLocked(
+                    fillResponse,
+                    ViewState.STATE_FILLABLE,
+                    /* clearResponse= */ false,
                     /* isPrimary= */ false);
 
             // Updates the UI, if necessary.
@@ -1997,16 +2126,15 @@
     private FillResponse createShallowCopy(
             FillResponse response, DatasetComputationContainer container) {
         return FillResponse.shallowCopy(
-                response,
-                new ArrayList<>(container.mDatasets),
-                getEligibleSaveInfo(response));
+                response, new ArrayList<>(container.mDatasets), getEligibleSaveInfo(response));
     }
 
     private SaveInfo getEligibleSaveInfo(FillResponse response) {
         SaveInfo saveInfo = response.getSaveInfo();
-        if (saveInfo == null || (!ArrayUtils.isEmpty(saveInfo.getOptionalIds())
-                || !ArrayUtils.isEmpty(saveInfo.getRequiredIds())
-                || (saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0)) {
+        if (saveInfo == null
+                || (!ArrayUtils.isEmpty(saveInfo.getOptionalIds())
+                        || !ArrayUtils.isEmpty(saveInfo.getRequiredIds())
+                        || (saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0)) {
             return saveInfo;
         }
         synchronized (mLock) {
@@ -2019,12 +2147,12 @@
             ArraySet<AutofillId> ids = new ArraySet<>();
             int saveType = saveInfo.getType();
             if (saveType == SaveInfo.SAVE_DATA_TYPE_GENERIC) {
-                for (Set<AutofillId> autofillIds: hintsToAutofillIdMap.values()) {
+                for (Set<AutofillId> autofillIds : hintsToAutofillIdMap.values()) {
                     ids.addAll(autofillIds);
                 }
             } else {
                 Set<String> hints = HintsHelper.getHintsForSaveType(saveType);
-                for (Map.Entry<String, Set<AutofillId>> entry: hintsToAutofillIdMap.entrySet()) {
+                for (Map.Entry<String, Set<AutofillId>> entry : hintsToAutofillIdMap.entrySet()) {
                     String hint = entry.getKey();
                     if (hints.contains(hint)) {
                         ids.addAll(entry.getValue());
@@ -2039,9 +2167,7 @@
         }
     }
 
-    /**
-     * A private class to hold & compute datasets to be shown
-     */
+    /** A private class to hold & compute datasets to be shown */
     private static class DatasetComputationContainer {
         // List of all autofill ids that have a corresponding datasets
         Set<AutofillId> mAutofillIds = new LinkedHashSet<>();
@@ -2103,9 +2229,10 @@
     }
 
     /**
-     * Computes datasets that are eligible to be shown based on provider detections.
-     * Datasets are populated in the provided container for them to be later merged with the
-     * PCC eligible datasets based on preference strategy.
+     * Computes datasets that are eligible to be shown based on provider detections. Datasets are
+     * populated in the provided container for them to be later merged with the PCC eligible
+     * datasets based on preference strategy.
+     *
      * @param response
      * @param container
      */
@@ -2210,9 +2337,10 @@
     }
 
     /**
-     * Computes datasets that are eligible to be shown based on PCC detections.
-     * Datasets are populated in the provided container for them to be later merged with the
-     * provider eligible datasets based on preference strategy.
+     * Computes datasets that are eligible to be shown based on PCC detections. Datasets are
+     * populated in the provided container for them to be later merged with the provider eligible
+     * datasets based on preference strategy.
+     *
      * @param response
      * @param container
      */
@@ -2267,14 +2395,21 @@
                         // For that, there has to be a datatype detected by PCC, and the dataset
                         // for that datatype provided by the provider.
                         AutofillId autofillId = dataset.getFieldIds().get(j);
-                        if (!mClassificationState.mClassificationCombinedHintsMap
-                                .containsKey(autofillId)) {
+                        if (!mClassificationState.mClassificationCombinedHintsMap.containsKey(
+                                autofillId)) {
                             additionalEligibleAutofillIds.add(autofillId);
                             additionalDatasetAutofillIds.add(autofillId);
                             // For each of the field, copy over values.
-                            copyFieldsFromDataset(dataset, j, autofillId, fieldIds, fieldValues,
-                                    fieldPresentations, fieldDialogPresentations,
-                                    fieldInlinePresentations, fieldInlineTooltipPresentations,
+                            copyFieldsFromDataset(
+                                    dataset,
+                                    j,
+                                    autofillId,
+                                    fieldIds,
+                                    fieldValues,
+                                    fieldPresentations,
+                                    fieldDialogPresentations,
+                                    fieldInlinePresentations,
+                                    fieldInlineTooltipPresentations,
                                     fieldFilters);
                         }
                         continue;
@@ -2292,9 +2427,16 @@
                             eligibleAutofillIds.add(autofillId);
                             datasetAutofillIds.add(autofillId);
                             // For each of the field, copy over values.
-                            copyFieldsFromDataset(dataset, j, autofillId, fieldIds, fieldValues,
-                                    fieldPresentations, fieldDialogPresentations,
-                                    fieldInlinePresentations, fieldInlineTooltipPresentations,
+                            copyFieldsFromDataset(
+                                    dataset,
+                                    j,
+                                    autofillId,
+                                    fieldIds,
+                                    fieldValues,
+                                    fieldPresentations,
+                                    fieldDialogPresentations,
+                                    fieldInlinePresentations,
+                                    fieldInlineTooltipPresentations,
                                     fieldFilters);
                         }
                     }
@@ -2364,8 +2506,7 @@
         fieldPresentations.add(dataset.getFieldPresentation(index));
         fieldDialogPresentations.add(dataset.getFieldDialogPresentation(index));
         fieldInlinePresentations.add(dataset.getFieldInlinePresentation(index));
-        fieldInlineTooltipPresentations.add(
-                dataset.getFieldInlineTooltipPresentation(index));
+        fieldInlineTooltipPresentations.add(dataset.getFieldInlineTooltipPresentation(index));
         fieldFilters.add(dataset.getFilter(index));
     }
 
@@ -2395,16 +2536,22 @@
 
             unregisterDelayedFillBroadcastLocked();
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
-                        + ") rejected - session: " + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillRequestFailureOrTimeout(req="
+                                + requestId
+                                + ") rejected - session: "
+                                + id
+                                + " destroyed");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
 
                 return;
             }
             if (sDebug) {
-                Slog.d(TAG, "finishing session due to service "
-                        + (timedOut ? "timeout" : "failure"));
+                Slog.d(
+                        TAG,
+                        "finishing session due to service " + (timedOut ? "timeout" : "failure"));
             }
             mService.resetLastResponse();
             mLastFillDialogTriggerIds = null;
@@ -2418,12 +2565,16 @@
                 final int targetSdk = mService.getTargedSdkLocked();
                 if (targetSdk >= Build.VERSION_CODES.Q) {
                     showMessage = false;
-                    Slog.w(TAG, "onFillRequestFailureOrTimeout(): not showing '" + message
-                            + "' because service's targetting API " + targetSdk);
+                    Slog.w(
+                            TAG,
+                            "onFillRequestFailureOrTimeout(): not showing '"
+                                    + message
+                                    + "' because service's targeting API "
+                                    + targetSdk);
                 }
                 if (message != null) {
-                    requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN,
-                            message.length());
+                    requestLog.addTaggedData(
+                            MetricsEvent.FIELD_AUTOFILL_TEXT_LEN, message.length());
                 }
             }
 
@@ -2445,8 +2596,8 @@
             mFillResponseEventLogger.maybeSetLatencyResponseProcessingMillis();
             mFillResponseEventLogger.logAndEndEvent();
         }
-        notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED,
-                /* autofillableIds= */ null);
+        notifyUnavailableToClient(
+                AutofillManager.STATE_UNKNOWN_FAILED, /* autofillableIds= */ null);
         if (showMessage) {
             getUiForShowing().showError(message, this);
         }
@@ -2455,8 +2606,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onSaveRequestSuccess(@NonNull String servicePackageName,
-            @Nullable IntentSender intentSender) {
+    public void onSaveRequestSuccess(
+            @NonNull String servicePackageName, @Nullable IntentSender intentSender) {
         synchronized (mLock) {
             mSessionFlags.mShowingSaveUi = false;
             // Log onSaveRequest result.
@@ -2464,16 +2615,22 @@
             mSaveEventLogger.maybeSetLatencySaveFinishMillis();
             mSaveEventLogger.logAndEndEvent();
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onSaveRequestSuccess() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
         }
-        LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
-                .setType(intentSender == null ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_OPEN);
+        LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
+                        .setType(
+                                intentSender == null
+                                        ? MetricsEvent.TYPE_SUCCESS
+                                        : MetricsEvent.TYPE_OPEN);
         mMetricsLogger.write(log);
 
-
         if (intentSender != null) {
             if (sDebug) Slog.d(TAG, "Starting intent sender on save()");
             startIntentSenderAndFinishSession(intentSender);
@@ -2485,8 +2642,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onSaveRequestFailure(@Nullable CharSequence message,
-            @NonNull String servicePackageName) {
+    public void onSaveRequestFailure(
+            @Nullable CharSequence message, @NonNull String servicePackageName) {
         boolean showMessage = !TextUtils.isEmpty(message);
 
         synchronized (mLock) {
@@ -2495,28 +2652,34 @@
             mSaveEventLogger.maybeSetLatencySaveFinishMillis();
             mSaveEventLogger.logAndEndEvent();
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onSaveRequestFailure() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (showMessage) {
                 final int targetSdk = mService.getTargedSdkLocked();
                 if (targetSdk >= Build.VERSION_CODES.Q) {
                     showMessage = false;
-                    Slog.w(TAG, "onSaveRequestFailure(): not showing '" + message
-                            + "' because service's targetting API " + targetSdk);
+                    Slog.w(
+                            TAG,
+                            "onSaveRequestFailure(): not showing '"
+                                    + message
+                                    + "' because service's targeting API "
+                                    + targetSdk);
                 }
             }
         }
         final LogMaker log =
                 newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_FAILURE);
+                        .setType(MetricsEvent.TYPE_FAILURE);
         if (message != null) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN, message.length());
         }
         mMetricsLogger.write(log);
 
-
         if (showMessage) {
             getUiForShowing().showError(message, this);
         }
@@ -2525,8 +2688,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
-            convertCredentialResponse) {
+    public void onConvertCredentialRequestSuccess(
+            @NonNull ConvertCredentialResponse convertCredentialResponse) {
         Dataset dataset = convertCredentialResponse.getDataset();
         Bundle clientState = convertCredentialResponse.getClientState();
         if (dataset != null) {
@@ -2534,15 +2697,18 @@
             if (clientState != null) {
                 requestId = clientState.getInt(EXTRA_AUTOFILL_REQUEST_ID);
             } else {
-                Slog.e(TAG, "onConvertCredentialRequestSuccess(): client state is null, this "
-                        + "would cause loss in logging.");
+                Slog.e(
+                        TAG,
+                        "onConvertCredentialRequestSuccess(): client state is null, this "
+                                + "would cause loss in logging.");
             }
             // TODO: Add autofill related logging; consider whether to log the index
-            fill(requestId, /* datasetIndex=*/ -1, dataset, UI_TYPE_CREDMAN_BOTTOM_SHEET);
+            fill(requestId, /* datasetIndex= */ -1, dataset, UI_TYPE_CREDMAN_BOTTOM_SHEET);
         } else {
             // TODO: Add logging to log this error case
-            Slog.e(TAG, "onConvertCredentialRequestSuccess(): dataset inside response is "
-                    + "null");
+            Slog.e(
+                    TAG,
+                    "onConvertCredentialRequestSuccess(): dataset inside response is " + "null");
         }
     }
 
@@ -2550,11 +2716,11 @@
      * Gets the {@link FillContext} for a request.
      *
      * @param requestId The id of the request
-     *
      * @return The context or {@code null} if there is no context
      */
     @GuardedBy("mLock")
-    @Nullable private FillContext getFillContextByRequestIdLocked(int requestId) {
+    @Nullable
+    private FillContext getFillContextByRequestIdLocked(int requestId) {
         if (mContexts == null) {
             return null;
         }
@@ -2582,19 +2748,26 @@
 
     // AutoFillUiCallback
     @Override
-    public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras,
-            int uiType) {
+    public void authenticate(
+            int requestId, int datasetIndex, IntentSender intent, Bundle extras, int uiType) {
         if (sDebug) {
-            Slog.d(TAG, "authenticate(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
-                    + "; intentSender=" + intent);
+            Slog.d(
+                    TAG,
+                    "authenticate(): requestId="
+                            + requestId
+                            + "; datasetIdx="
+                            + datasetIndex
+                            + "; intentSender="
+                            + intent);
         }
         final Intent fillInIntent;
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetAuthenticationType(
-                AUTHENTICATION_TYPE_FULL_AUTHENTICATION);
+                    AUTHENTICATION_TYPE_FULL_AUTHENTICATION);
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#authenticate() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#authenticate() rejected - session: " + id + " destroyed");
                 return;
             }
             fillInIntent = createAuthFillInIntentLocked(requestId, extras);
@@ -2607,10 +2780,14 @@
         mService.setAuthenticationSelected(id, mClientState, uiType);
 
         final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
-        mHandler.sendMessage(obtainMessage(
-                Session::startAuthentication,
-                this, authenticationId, intent, fillInIntent,
-                /* authenticateInline= */ uiType == UI_TYPE_INLINE));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::startAuthentication,
+                        this,
+                        authenticationId,
+                        intent,
+                        fillInIntent,
+                        /* authenticateInline= */ uiType == UI_TYPE_INLINE));
     }
 
     // AutoFillUiCallback
@@ -2618,14 +2795,13 @@
     public void fill(int requestId, int datasetIndex, Dataset dataset, int uiType) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#fill() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#fill() rejected - session: " + id + " destroyed");
                 return;
             }
         }
-        mHandler.sendMessage(obtainMessage(
-                Session::autoFill,
-                this, requestId, datasetIndex, dataset, true, uiType));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::autoFill, this, requestId, datasetIndex, dataset, true, uiType));
     }
 
     // AutoFillUiCallback
@@ -2633,15 +2809,13 @@
     public void save() {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#save() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#save() rejected - session: " + id + " destroyed");
                 return;
             }
             mSaveEventLogger.maybeSetLatencySaveRequestMillis();
         }
-        mHandler.sendMessage(obtainMessage(
-                AutofillManagerServiceImpl::handleSessionSave,
-                mService, this));
+        mHandler.sendMessage(
+                obtainMessage(AutofillManagerServiceImpl::handleSessionSave, mService, this));
     }
 
     // AutoFillUiCallback
@@ -2650,13 +2824,13 @@
         synchronized (mLock) {
             mSessionFlags.mShowingSaveUi = false;
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#cancelSave() rejected - session: " + id + " destroyed");
                 return;
             }
         }
-        mHandler.sendMessage(obtainMessage(
-                Session::removeFromService, this));
+        mHandler.sendMessage(obtainMessage(Session::removeFromService, this));
     }
 
     // AutofillUiCallback
@@ -2692,26 +2866,34 @@
 
     // AutoFillUiCallback
     @Override
-    public void requestShowFillUi(AutofillId id, int width, int height,
-            IAutofillWindowPresenter presenter) {
+    public void requestShowFillUi(
+            AutofillId id, int width, int height, IAutofillWindowPresenter presenter) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#requestShowFillUi() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#requestShowFillUi() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (id.equals(mCurrentViewId)) {
                 try {
                     final ViewState view = mViewStates.get(id);
-                    mClient.requestShowFillUi(this.id, id, width, height, view.getVirtualBounds(),
-                            presenter);
+                    mClient.requestShowFillUi(
+                            this.id, id, width, height, view.getVirtualBounds(), presenter);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error requesting to show fill UI", e);
                 }
             } else {
                 if (sDebug) {
-                    Slog.d(TAG, "Do not show full UI on " + id + " as it is not the current view ("
-                            + mCurrentViewId + ") anymore");
+                    Slog.d(
+                            TAG,
+                            "Do not show full UI on "
+                                    + id
+                                    + " as it is not the current view ("
+                                    + mCurrentViewId
+                                    + ") anymore");
                 }
             }
         }
@@ -2722,8 +2904,11 @@
     public void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#dispatchUnhandledKey() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#dispatchUnhandledKey() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (id.equals(mCurrentViewId)) {
@@ -2733,8 +2918,13 @@
                     Slog.e(TAG, "Error requesting to dispatch unhandled key", e);
                 }
             } else {
-                Slog.w(TAG, "Do not dispatch unhandled key on " + id
-                        + " as it is not the current view (" + mCurrentViewId + ") anymore");
+                Slog.w(
+                        TAG,
+                        "Do not dispatch unhandled key on "
+                                + id
+                                + " as it is not the current view ("
+                                + mCurrentViewId
+                                + ") anymore");
             }
         }
     }
@@ -2790,17 +2980,19 @@
     public void startIntentSender(IntentSender intentSender, Intent intent) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#startIntentSender() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#startIntentSender() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (intent == null) {
                 removeFromServiceLocked();
             }
         }
-        mHandler.sendMessage(obtainMessage(
-                Session::doStartIntentSender,
-                this, intentSender, intent));
+        mHandler.sendMessage(
+                obtainMessage(Session::doStartIntentSender, this, intentSender, intent));
     }
 
     // AutoFillUiCallback
@@ -2865,13 +3057,17 @@
     @GuardedBy("mLock")
     void setAuthenticationResultLocked(Bundle data, int authenticationId) {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#setAuthenticationResultLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#setAuthenticationResultLocked() rejected - session: "
+                            + id
+                            + " destroyed");
             return;
         }
         if (sDebug) {
-            Slog.d(TAG, "setAuthenticationResultLocked(): id= " + authenticationId
-                    + ", data=" + data);
+            Slog.d(
+                    TAG,
+                    "setAuthenticationResultLocked(): id= " + authenticationId + ", data=" + data);
         }
         final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
         if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) {
@@ -2890,9 +3086,10 @@
             removeFromService();
             return;
         }
-        final FillResponse authenticatedResponse = mRequestId.isSecondaryProvider(requestId)
-                ? mSecondaryResponses.get(requestId)
-                : mResponses.get(requestId);
+        final FillResponse authenticatedResponse =
+                mRequestId.isSecondaryProvider(requestId)
+                        ? mSecondaryResponses.get(requestId)
+                        : mResponses.get(requestId);
         if (authenticatedResponse == null || data == null) {
             Slog.w(TAG, "no authenticated response");
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2902,8 +3099,7 @@
             return;
         }
 
-        final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(
-                authenticationId);
+        final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(authenticationId);
         Dataset dataset = null;
         // Authenticated a dataset - reset view state regardless if we got a response or a dataset
         if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
@@ -2922,33 +3118,45 @@
         mSessionFlags.mExpiredResponse = false;
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
-        final GetCredentialException exception = data.getSerializable(
-                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
-                GetCredentialException.class);
+        final GetCredentialException exception =
+                data.getSerializable(
+                        CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                        GetCredentialException.class);
 
         final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
         if (sDebug) {
-            Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result
-                    + ", clientState=" + newClientState + ", authenticationId=" + authenticationId);
+            Slog.d(
+                    TAG,
+                    "setAuthenticationResultLocked(): result="
+                            + result
+                            + ", clientState="
+                            + newClientState
+                            + ", authenticationId="
+                            + authenticationId);
         }
-        if (Flags.autofillCredmanDevIntegration() && exception != null
+        if (Flags.autofillCredmanDevIntegration()
+                && exception != null
                 && !exception.getType().equals(GetCredentialException.TYPE_USER_CANCELED)) {
             if (dataset != null && dataset.getFieldIds().size() == 1) {
                 if (sDebug) {
-                    Slog.d(TAG, "setAuthenticationResultLocked(): result returns with"
-                            + "Credential Manager Exception");
+                    Slog.d(
+                            TAG,
+                            "setAuthenticationResultLocked(): result returns with"
+                                    + "Credential Manager Exception");
                 }
                 AutofillId autofillId = dataset.getFieldIds().get(0);
-                sendCredentialManagerResponseToApp(/*response=*/ null,
-                        (GetCredentialException) exception, autofillId);
+                sendCredentialManagerResponseToApp(
+                        /* response= */ null, (GetCredentialException) exception, autofillId);
             }
             return;
         }
 
         if (result instanceof FillResponse) {
             if (sDebug) {
-                Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from"
-                        + " authentication flow");
+                Slog.d(
+                        TAG,
+                        "setAuthenticationResultLocked(): received FillResponse from"
+                                + " authentication flow");
             }
             logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2963,33 +3171,40 @@
                 if (dataset != null && dataset.getFieldIds().size() == 1) {
                     AutofillId autofillId = dataset.getFieldIds().get(0);
                     if (sDebug) {
-                        Slog.d(TAG, "Received GetCredentialResponse from authentication flow,"
-                                + "for autofillId: " + autofillId);
+                        Slog.d(
+                                TAG,
+                                "Received GetCredentialResponse from authentication flow,"
+                                        + "for autofillId: "
+                                        + autofillId);
                     }
-                    sendCredentialManagerResponseToApp(response,
-                            /*exception=*/ null, autofillId);
+                    sendCredentialManagerResponseToApp(response, /* exception= */ null, autofillId);
                 }
             } else if (Flags.autofillCredmanIntegration()) {
-                Dataset datasetFromCredentialResponse = getDatasetFromCredentialResponse(
-                        (GetCredentialResponse) result);
+                Dataset datasetFromCredentialResponse =
+                        getDatasetFromCredentialResponse((GetCredentialResponse) result);
                 if (datasetFromCredentialResponse != null) {
-                    autoFill(requestId, datasetIdx, datasetFromCredentialResponse,
-                            false, UI_TYPE_UNKNOWN);
+                    autoFill(
+                            requestId,
+                            datasetIdx,
+                            datasetFromCredentialResponse,
+                            false,
+                            UI_TYPE_UNKNOWN);
                 }
             }
         } else if (result instanceof Dataset) {
             if (sDebug) {
-                Slog.d(TAG, "setAuthenticationResultLocked(): received Dataset from"
-                        + " authentication flow");
+                Slog.d(
+                        TAG,
+                        "setAuthenticationResultLocked(): received Dataset from"
+                                + " authentication flow");
             }
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-                logAuthenticationStatusLocked(requestId,
-                        MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+                logAuthenticationStatusLocked(
+                        requestId, MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
                 mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                         AUTHENTICATION_RESULT_SUCCESS);
                 if (newClientState != null) {
-                    if (sDebug)
-                        Slog.d(TAG, "Updating client state from auth dataset");
+                    if (sDebug) Slog.d(TAG, "Updating client state from auth dataset");
                     mClientState = newClientState;
                 }
                 Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result);
@@ -2999,10 +3214,14 @@
                 }
                 autoFill(requestId, datasetIdx, datasetFromResult, false, UI_TYPE_UNKNOWN);
             } else {
-                Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id "
-                        + authenticationId);
-                logAuthenticationStatusLocked(requestId,
-                        MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
+                Slog.w(
+                        TAG,
+                        "invalid index ("
+                                + datasetIdx
+                                + ") for authentication id "
+                                + authenticationId);
+                logAuthenticationStatusLocked(
+                        requestId, MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
                 mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                         AUTHENTICATION_RESULT_FAILURE);
             }
@@ -3010,8 +3229,7 @@
             if (result != null) {
                 Slog.w(TAG, "service returned invalid auth type: " + result);
             }
-            logAuthenticationStatusLocked(requestId,
-                    MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
+            logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                     AUTHENTICATION_RESULT_FAILURE);
             processNullResponseLocked(requestId, 0);
@@ -3036,8 +3254,10 @@
             Slog.d(TAG, "DBG: authenticated effective response: " + response);
         }
         if (response == null || response.getDatasets().size() == 0) {
-            Log.wtf(TAG, "No datasets in fill response on authentication. response = "
-                    + (response == null ? "null" : response.toString()));
+            Log.wtf(
+                    TAG,
+                    "No datasets in fill response on authentication. response = "
+                            + (response == null ? "null" : response.toString()));
             return authenticatedDataset;
         }
         List<Dataset> datasets = response.getDatasets();
@@ -3047,8 +3267,10 @@
             for (Dataset dataset : datasets) {
                 if (!dataset.getFieldIds().isEmpty()) {
                     for (int i = 0; i < dataset.getFieldIds().size(); i++) {
-                        builder.setField(dataset.getFieldIds().get(i),
-                                new Field.Builder().setValue(dataset.getFieldValues().get(i))
+                        builder.setField(
+                                dataset.getFieldIds().get(i),
+                                new Field.Builder()
+                                        .setValue(dataset.getFieldValues().get(i))
                                         .build());
                     }
                 }
@@ -3063,12 +3285,11 @@
     }
 
     /**
-     * Returns whether the dataset returned from the authentication result is ephemeral or not.
-     * See {@link AutofillManager#EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET} for more
-     * information.
+     * Returns whether the dataset returned from the authentication result is ephemeral or not. See
+     * {@link AutofillManager#EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET} for more information.
      */
-    private static boolean isAuthResultDatasetEphemeral(@Nullable Dataset oldDataset,
-            @NonNull Bundle authResultData) {
+    private static boolean isAuthResultDatasetEphemeral(
+            @Nullable Dataset oldDataset, @NonNull Bundle authResultData) {
         if (authResultData.containsKey(
                 AutofillManager.EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET)) {
             return authResultData.getBoolean(
@@ -3079,11 +3300,11 @@
 
     /**
      * A dataset can potentially have multiple fields, and it's possible that some of the fields'
-     * has inline presentation and some don't. It's also possible that some of the fields'
-     * inline presentation is pinned and some isn't. So the concept of whether a dataset is
-     * pinned or not is ill-defined. Here we say a dataset is pinned if any of the field has a
-     * pinned inline presentation in the dataset. It's not ideal but hopefully it is sufficient
-     * for most of the cases.
+     * has inline presentation and some don't. It's also possible that some of the fields' inline
+     * presentation is pinned and some isn't. So the concept of whether a dataset is pinned or not
+     * is ill-defined. Here we say a dataset is pinned if any of the field has a pinned inline
+     * presentation in the dataset. It's not ideal but hopefully it is sufficient for most of the
+     * cases.
      */
     private static boolean isPinnedDataset(@Nullable Dataset dataset) {
         if (dataset != null && dataset.getFieldIds() != null) {
@@ -3100,16 +3321,30 @@
 
     @GuardedBy("mLock")
     void setAuthenticationResultForAugmentedAutofillLocked(Bundle data, int authId) {
-        final Dataset dataset = (data == null) ? null :
-                data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT, android.service.autofill.Dataset.class);
+        final Dataset dataset =
+                (data == null)
+                        ? null
+                        : data.getParcelable(
+                                AutofillManager.EXTRA_AUTHENTICATION_RESULT,
+                                android.service.autofill.Dataset.class);
         if (sDebug) {
-            Slog.d(TAG, "Auth result for augmented autofill: sessionId=" + id
-                    + ", authId=" + authId + ", dataset=" + dataset);
+            Slog.d(
+                    TAG,
+                    "Auth result for augmented autofill: sessionId="
+                            + id
+                            + ", authId="
+                            + authId
+                            + ", dataset="
+                            + dataset);
         }
-        final AutofillId fieldId = (dataset != null && dataset.getFieldIds().size() == 1)
-                ? dataset.getFieldIds().get(0) : null;
-        final AutofillValue value = (dataset != null && dataset.getFieldValues().size() == 1)
-                ? dataset.getFieldValues().get(0) : null;
+        final AutofillId fieldId =
+                (dataset != null && dataset.getFieldIds().size() == 1)
+                        ? dataset.getFieldIds().get(0)
+                        : null;
+        final AutofillValue value =
+                (dataset != null && dataset.getFieldValues().size() == 1)
+                        ? dataset.getFieldValues().get(0)
+                        : null;
         final ClipData content = (dataset != null) ? dataset.getFieldContent() : null;
         if (fieldId == null || (value == null && content == null)) {
             if (sDebug) {
@@ -3154,8 +3389,14 @@
 
         // Fill the value into the field.
         if (sDebug) {
-            Slog.d(TAG, "Filling after auth: fieldId=" + fieldId + ", value=" + value
-                    + ", content=" + content);
+            Slog.d(
+                    TAG,
+                    "Filling after auth: fieldId="
+                            + fieldId
+                            + ", value="
+                            + value
+                            + ", content="
+                            + content);
         }
         try {
             if (content != null) {
@@ -3164,8 +3405,15 @@
                 mClient.autofill(id, dataset.getFieldIds(), dataset.getFieldValues(), true);
             }
         } catch (RemoteException e) {
-            Slog.w(TAG, "Error filling after auth: fieldId=" + fieldId + ", value=" + value
-                    + ", content=" + content, e);
+            Slog.w(
+                    TAG,
+                    "Error filling after auth: fieldId="
+                            + fieldId
+                            + ", value="
+                            + value
+                            + ", content="
+                            + content,
+                    e);
         }
 
         // Clear the suggestions since the user already accepted one of them.
@@ -3175,8 +3423,11 @@
     @GuardedBy("mLock")
     void setHasCallbackLocked(boolean hasIt) {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#setHasCallbackLocked() rejected - session: "
+                            + id
+                            + " destroyed");
             return;
         }
         mHasCallback = hasIt;
@@ -3185,9 +3436,8 @@
     @GuardedBy("mLock")
     @Nullable
     private FillResponse getLastResponseLocked(@Nullable String logPrefixFmt) {
-        final String logPrefix = sDebug && logPrefixFmt != null
-                ? String.format(logPrefixFmt, this.id)
-                : null;
+        final String logPrefix =
+                sDebug && logPrefixFmt != null ? String.format(logPrefixFmt, this.id) : null;
         if (mContexts == null) {
             if (logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
             return null;
@@ -3204,16 +3454,28 @@
         final int lastResponseIdx = getLastResponseIndexLocked();
         if (lastResponseIdx < 0) {
             if (logPrefix != null) {
-                Slog.w(TAG, logPrefix + ": did not get last response. mResponses=" + mResponses
-                        + ", mViewStates=" + mViewStates);
+                Slog.w(
+                        TAG,
+                        logPrefix
+                                + ": did not get last response. mResponses="
+                                + mResponses
+                                + ", mViewStates="
+                                + mViewStates);
             }
             return null;
         }
 
         final FillResponse response = mResponses.valueAt(lastResponseIdx);
         if (sVerbose && logPrefix != null) {
-            Slog.v(TAG, logPrefix + ": mResponses=" + mResponses + ", mContexts=" + mContexts
-                    + ", mViewStates=" + mViewStates);
+            Slog.v(
+                    TAG,
+                    logPrefix
+                            + ": mResponses="
+                            + mResponses
+                            + ", mContexts="
+                            + mContexts
+                            + ", mViewStates="
+                            + mViewStates);
         }
         return response;
     }
@@ -3232,9 +3494,8 @@
     }
 
     /**
-     * Get statistic information of save info in current session. Specifically
-     *   1. how many save info the current session has.
-     *   2. How many distinct save data types current session has.
+     * Get statistic information of save info in current session. Specifically 1. how many save info
+     * the current session has. 2. How many distinct save data types current session has.
      *
      * @return SaveInfoStats returns the above two number in a SaveInfoStats object
      */
@@ -3255,12 +3516,21 @@
      */
     public void logContextCommitted() {
         if (sVerbose) {
-            Slog.v(TAG, "logContextCommitted (" + id + "): commit_reason:" + COMMIT_REASON_UNKNOWN
-                    + " no_save_reason:" + Event.NO_SAVE_UI_REASON_NONE);
+            Slog.v(
+                    TAG,
+                    "logContextCommitted ("
+                            + id
+                            + "): commit_reason:"
+                            + COMMIT_REASON_UNKNOWN
+                            + " no_save_reason:"
+                            + Event.NO_SAVE_UI_REASON_NONE);
         }
-        mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
-                Event.NO_SAVE_UI_REASON_NONE,
-                COMMIT_REASON_UNKNOWN));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::handleLogContextCommitted,
+                        this,
+                        Event.NO_SAVE_UI_REASON_NONE,
+                        COMMIT_REASON_UNKNOWN));
         synchronized (mLock) {
             logAllEventsLocked(COMMIT_REASON_UNKNOWN);
         }
@@ -3274,16 +3544,25 @@
      * @param saveDialogNotShowReason The reason why a save dialog was not shown.
      * @param commitReason The reason why context is committed.
      */
-
     @GuardedBy("mLock")
-    public void logContextCommittedLocked(@NoSaveReason int saveDialogNotShowReason,
-            @AutofillCommitReason int commitReason) {
+    public void logContextCommittedLocked(
+            @NoSaveReason int saveDialogNotShowReason, @AutofillCommitReason int commitReason) {
         if (sVerbose) {
-            Slog.v(TAG, "logContextCommittedLocked (" + id + "): commit_reason:" + commitReason
-                    + " no_save_reason:" + saveDialogNotShowReason);
+            Slog.v(
+                    TAG,
+                    "logContextCommittedLocked ("
+                            + id
+                            + "): commit_reason:"
+                            + commitReason
+                            + " no_save_reason:"
+                            + saveDialogNotShowReason);
         }
-        mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
-                saveDialogNotShowReason, commitReason));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::handleLogContextCommitted,
+                        this,
+                        saveDialogNotShowReason,
+                        commitReason));
 
         mSessionCommittedEventLogger.maybeSetCommitReason(commitReason);
         mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
@@ -3295,8 +3574,8 @@
         mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NONE);
     }
 
-    private void handleLogContextCommitted(@NoSaveReason int saveDialogNotShowReason,
-            @AutofillCommitReason int commitReason) {
+    private void handleLogContextCommitted(
+            @NoSaveReason int saveDialogNotShowReason, @AutofillCommitReason int commitReason) {
         final FillResponse lastResponse;
         synchronized (mLock) {
             lastResponse = getLastResponseLocked("logContextCommited(%s)");
@@ -3326,31 +3605,42 @@
 
         // Sets field classification scores
         if (userData != null && fcStrategy != null) {
-            logFieldClassificationScore(fcStrategy, userData, saveDialogNotShowReason,
-                    commitReason);
+            logFieldClassificationScore(
+                    fcStrategy, userData, saveDialogNotShowReason, commitReason);
         } else {
             logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
         }
     }
 
-    private void logContextCommitted(@Nullable ArrayList<AutofillId> detectedFieldIds,
+    private void logContextCommitted(
+            @Nullable ArrayList<AutofillId> detectedFieldIds,
             @Nullable ArrayList<FieldClassification> detectedFieldClassifications,
             @NoSaveReason int saveDialogNotShowReason,
             @AutofillCommitReason int commitReason) {
         synchronized (mLock) {
-            logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications,
-                    saveDialogNotShowReason, commitReason);
+            logContextCommittedLocked(
+                    detectedFieldIds,
+                    detectedFieldClassifications,
+                    saveDialogNotShowReason,
+                    commitReason);
         }
     }
 
     @GuardedBy("mLock")
-    private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
+    private void logContextCommittedLocked(
+            @Nullable ArrayList<AutofillId> detectedFieldIds,
             @Nullable ArrayList<FieldClassification> detectedFieldClassifications,
             @NoSaveReason int saveDialogNotShowReason,
             @AutofillCommitReason int commitReason) {
         if (sVerbose) {
-            Slog.v(TAG, "logContextCommittedLocked (" + id + "): commit_reason:" + commitReason
-                    + " no_save_reason:" + saveDialogNotShowReason);
+            Slog.v(
+                    TAG,
+                    "logContextCommittedLocked ("
+                            + id
+                            + "): commit_reason:"
+                            + commitReason
+                            + " no_save_reason:"
+                            + saveDialogNotShowReason);
         }
         final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)");
         if (lastResponse == null) return;
@@ -3423,8 +3713,11 @@
                     final AutofillValue currentValue = viewState.getCurrentValue();
                     if (autofilledValue != null && autofilledValue.equals(currentValue)) {
                         if (sDebug) {
-                            Slog.d(TAG, "logContextCommitted(): ignoring changed " + viewState
-                                    + " because it has same value that was autofilled");
+                            Slog.d(
+                                    TAG,
+                                    "logContextCommitted(): ignoring changed "
+                                            + viewState
+                                            + " because it has same value that was autofilled");
                         }
                         continue;
                     }
@@ -3442,8 +3735,12 @@
                     final AutofillValue currentValue = viewState.getCurrentValue();
                     if (currentValue == null) {
                         if (sDebug) {
-                            Slog.d(TAG, "logContextCommitted(): skipping view without current "
-                                    + "value ( " + viewState + ")");
+                            Slog.d(
+                                    TAG,
+                                    "logContextCommitted(): skipping view without current "
+                                            + "value ( "
+                                            + viewState
+                                            + ")");
                         }
                         continue;
                     }
@@ -3455,7 +3752,7 @@
                             final List<Dataset> datasets = response.getDatasets();
                             if (datasets == null || datasets.isEmpty()) {
                                 if (sVerbose) {
-                                    Slog.v(TAG,  "logContextCommitted() no datasets at " + j);
+                                    Slog.v(TAG, "logContextCommitted() no datasets at " + j);
                                 }
                             } else {
                                 for (int k = 0; k < datasets.size(); k++) {
@@ -3463,8 +3760,11 @@
                                     final String datasetId = dataset.getId();
                                     if (datasetId == null) {
                                         if (sVerbose) {
-                                            Slog.v(TAG, "logContextCommitted() skipping idless "
-                                                    + "dataset " + dataset);
+                                            Slog.v(
+                                                    TAG,
+                                                    "logContextCommitted() skipping idless "
+                                                            + "dataset "
+                                                            + dataset);
                                         }
                                     } else {
                                         final ArrayList<AutofillValue> values =
@@ -3473,9 +3773,13 @@
                                             final AutofillValue candidate = values.get(l);
                                             if (currentValue.equals(candidate)) {
                                                 if (sDebug) {
-                                                    Slog.d(TAG, "field " + viewState.id + " was "
-                                                            + "manually filled with value set by "
-                                                            + "dataset " + datasetId);
+                                                    Slog.d(
+                                                            TAG,
+                                                            "field "
+                                                                    + viewState.id
+                                                                    + " was manually filled with"
+                                                                    + " value set by dataset "
+                                                                    + datasetId);
                                                 }
                                                 if (manuallyFilledIds == null) {
                                                     manuallyFilledIds = new ArrayMap<>();
@@ -3524,10 +3828,20 @@
             }
         }
 
-        mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
-                changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
-                manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                mComponentName, mCompatMode, saveDialogNotShowReason);
+        mService.logContextCommittedLocked(
+                id,
+                mClientState,
+                mSelectedDatasetIds,
+                ignoredDatasets,
+                changedFieldIds,
+                changedDatasetIds,
+                manuallyFilledFieldIds,
+                manuallyFilledDatasetIds,
+                detectedFieldIds,
+                detectedFieldClassifications,
+                mComponentName,
+                mCompatMode,
+                saveDialogNotShowReason);
         mSessionCommittedEventLogger.maybeSetCommitReason(commitReason);
         mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
         mSaveEventLogger.maybeSetSaveUiNotShownReason(saveDialogNotShowReason);
@@ -3537,7 +3851,8 @@
      * Adds the matches to {@code detectedFieldsIds} and {@code detectedFieldClassifications} for
      * {@code fieldId} based on its {@code currentValue} and {@code userData}.
      */
-    private void logFieldClassificationScore(@NonNull FieldClassificationStrategy fcStrategy,
+    private void logFieldClassificationScore(
+            @NonNull FieldClassificationStrategy fcStrategy,
             @NonNull FieldClassificationUserData userData,
             @NoSaveReason int saveDialogNotShowReason,
             @AutofillCommitReason int commitReason) {
@@ -3555,16 +3870,20 @@
         if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) {
             final int valuesLength = userValues == null ? -1 : userValues.length;
             final int idsLength = categoryIds == null ? -1 : categoryIds.length;
-            Slog.w(TAG, "setScores(): user data mismatch: values.length = "
-                    + valuesLength + ", ids.length = " + idsLength);
+            Slog.w(
+                    TAG,
+                    "setScores(): user data mismatch: values.length = "
+                            + valuesLength
+                            + ", ids.length = "
+                            + idsLength);
             return;
         }
 
         final int maxFieldsSize = UserData.getMaxFieldClassificationIdsSize();
 
         final ArrayList<AutofillId> detectedFieldIds = new ArrayList<>(maxFieldsSize);
-        final ArrayList<FieldClassification> detectedFieldClassifications = new ArrayList<>(
-                maxFieldsSize);
+        final ArrayList<FieldClassification> detectedFieldClassifications =
+                new ArrayList<>(maxFieldsSize);
 
         final Collection<ViewState> viewStates;
         synchronized (mLock) {
@@ -3583,33 +3902,49 @@
         }
 
         // Then use the results, asynchronously
-        final RemoteCallback callback = new RemoteCallback(
-                new LogFieldClassificationScoreOnResultListener(
-                        this,
-                        saveDialogNotShowReason,
-                        commitReason,
-                        viewsSize,
-                        autofillIds,
-                        userValues,
-                        categoryIds,
-                        detectedFieldIds,
-                        detectedFieldClassifications));
+        final RemoteCallback callback =
+                new RemoteCallback(
+                        new LogFieldClassificationScoreOnResultListener(
+                                this,
+                                saveDialogNotShowReason,
+                                commitReason,
+                                viewsSize,
+                                autofillIds,
+                                userValues,
+                                categoryIds,
+                                detectedFieldIds,
+                                detectedFieldClassifications));
 
-        fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
-                defaultAlgorithm, defaultArgs, algorithms, args);
+        fcStrategy.calculateScores(
+                callback,
+                currentValues,
+                userValues,
+                categoryIds,
+                defaultAlgorithm,
+                defaultArgs,
+                algorithms,
+                args);
     }
 
-    void handleLogFieldClassificationScore(@Nullable Bundle result, int saveDialogNotShowReason,
-            int commitReason, int viewsSize, AutofillId[] autofillIds, String[] userValues,
-            String[] categoryIds, ArrayList<AutofillId> detectedFieldIds,
+    void handleLogFieldClassificationScore(
+            @Nullable Bundle result,
+            int saveDialogNotShowReason,
+            int commitReason,
+            int viewsSize,
+            AutofillId[] autofillIds,
+            String[] userValues,
+            String[] categoryIds,
+            ArrayList<AutofillId> detectedFieldIds,
             ArrayList<FieldClassification> detectedFieldClassifications) {
         if (result == null) {
             if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
             logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
             return;
         }
-        final Scores scores = result.getParcelable(EXTRA_SCORES,
-                android.service.autofill.AutofillFieldClassificationService.Scores.class);
+        final Scores scores =
+                result.getParcelable(
+                        EXTRA_SCORES,
+                        android.service.autofill.AutofillFieldClassificationService.Scores.class);
         if (scores == null) {
             Slog.w(TAG, "No field classification score on " + result);
             return;
@@ -3633,14 +3968,24 @@
                         final Float currentScore = scoresByField.get(categoryId);
                         if (currentScore != null && currentScore > score) {
                             if (sVerbose) {
-                                Slog.v(TAG, "skipping score " + score
-                                        + " because it's less than " + currentScore);
+                                Slog.v(
+                                        TAG,
+                                        "skipping score "
+                                                + score
+                                                + " because it's less than "
+                                                + currentScore);
                             }
                             continue;
                         }
                         if (sVerbose) {
-                            Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
-                                    + autofillId);
+                            Slog.v(
+                                    TAG,
+                                    "adding score "
+                                            + score
+                                            + " at index "
+                                            + j
+                                            + " and id "
+                                            + autofillId);
                         }
                         scoresByField.put(categoryId, score);
                     } else if (sVerbose) {
@@ -3666,13 +4011,16 @@
             wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
             return;
         }
-        logContextCommitted(detectedFieldIds, detectedFieldClassifications,
-                saveDialogNotShowReason, commitReason);
+        logContextCommitted(
+                detectedFieldIds,
+                detectedFieldClassifications,
+                saveDialogNotShowReason,
+                commitReason);
     }
 
     /**
-     * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN}
-     * when necessary.
+     * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN} when
+     * necessary.
      *
      * <p>Note: It is necessary to call logContextCommitted() first before calling this method.
      */
@@ -3689,11 +4037,14 @@
     @NonNull
     public SaveResult showSaveLocked() {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#showSaveLocked() rejected - session: " + id + " destroyed");
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SESSION_DESTROYED);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ false,
                     Event.NO_SAVE_UI_REASON_NONE);
         }
         mSessionState = STATE_FINISHED;
@@ -3705,12 +4056,16 @@
          */
         if (mSessionFlags.mScreenHasCredmanField) {
             if (sVerbose) {
-                Slog.v(TAG, "Call to Session#showSaveLocked() rejected - "
-                        + "there is credman field in screen");
+                Slog.v(
+                        TAG,
+                        "Call to Session#showSaveLocked() rejected - "
+                                + "there is credman field in screen");
             }
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SCREEN_HAS_CREDMAN_FIELD);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ true,
                     Event.NO_SAVE_UI_REASON_NONE);
         }
 
@@ -3728,7 +4083,9 @@
             if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service");
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NO_SAVE_INFO);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ true,
                     Event.NO_SAVE_UI_REASON_NO_SAVE_INFO);
         }
 
@@ -3737,7 +4094,9 @@
             if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save");
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ false,
                     Event.NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG);
         }
 
@@ -3774,12 +4133,13 @@
                     // Some apps clear the form before navigating to other activities.
                     // If current value is empty, consider fall back to last cached
                     // non-empty result first.
-                    final AutofillValue candidateSaveValue =
-                            viewState.getCandidateSaveValue();
+                    final AutofillValue candidateSaveValue = viewState.getCandidateSaveValue();
                     if (candidateSaveValue != null && !candidateSaveValue.isEmpty()) {
                         if (sVerbose) {
-                            Slog.v(TAG, "current value is empty, using cached last non-empty "
-                                    + "value instead");
+                            Slog.v(
+                                    TAG,
+                                    "current value is empty, using cached last non-empty "
+                                            + "value instead");
                         }
                         value = candidateSaveValue;
                     } else {
@@ -3788,8 +4148,14 @@
                         final AutofillValue initialValue = getValueFromContextsLocked(id);
                         if (initialValue != null) {
                             if (sDebug) {
-                                Slog.d(TAG, "Value of required field " + id + " didn't change; "
-                                        + "using initial value (" + initialValue + ") instead");
+                                Slog.d(
+                                        TAG,
+                                        "Value of required field "
+                                                + id
+                                                + " didn't change; "
+                                                + "using initial value ("
+                                                + initialValue
+                                                + ") instead");
                             }
                             value = initialValue;
                         } else {
@@ -3821,8 +4187,13 @@
                         final AutofillValue initialValue = getValueFromContextsLocked(id);
                         if (initialValue != null && initialValue.equals(value)) {
                             if (sDebug) {
-                                Slog.d(TAG, "id " + id + " is part of dataset but initial value "
-                                        + "didn't change: " + value);
+                                Slog.d(
+                                        TAG,
+                                        "id "
+                                                + id
+                                                + " is part of dataset but initial value "
+                                                + "didn't change: "
+                                                + value);
                             }
                             changed = false;
                         } else {
@@ -3833,8 +4204,14 @@
                     }
                     if (changed) {
                         if (sDebug) {
-                            Slog.d(TAG, "found a change on required " + id + ": " + filledValue
-                                    + " => " + value);
+                            Slog.d(
+                                    TAG,
+                                    "found a change on required "
+                                            + id
+                                            + ": "
+                                            + filledValue
+                                            + " => "
+                                            + value);
                         }
                         atLeastOneChanged = true;
                     }
@@ -3844,8 +4221,12 @@
 
         final AutofillId[] optionalIds = saveInfo.getOptionalIds();
         if (sVerbose) {
-            Slog.v(TAG, "allRequiredAreNotEmpty: " + allRequiredAreNotEmpty + " hasOptional: "
-                    + (optionalIds != null));
+            Slog.v(
+                    TAG,
+                    "allRequiredAreNotEmpty: "
+                            + allRequiredAreNotEmpty
+                            + " hasOptional: "
+                            + (optionalIds != null));
         }
         int saveDialogNotShowReason;
         if (!allRequiredAreNotEmpty) {
@@ -3859,7 +4240,7 @@
             // - if at least one required id changed but it was not part of a filled dataset, we
             //   need to check if an optional id is part of a filled datased (in which case we show
             //   Update instead of Save)
-            if (optionalIds!= null && (!atLeastOneChanged || !isUpdate)) {
+            if (optionalIds != null && (!atLeastOneChanged || !isUpdate)) {
                 // No change on required ids yet, look for changes on optional ids.
                 for (int i = 0; i < optionalIds.length; i++) {
                     final AutofillId id = optionalIds[i];
@@ -3879,8 +4260,10 @@
                                     viewState.getCandidateSaveValue();
                             if (candidateSaveValue != null && !candidateSaveValue.isEmpty()) {
                                 if (sVerbose) {
-                                    Slog.v(TAG, "current value is empty, using cached last "
-                                            + "non-empty value instead");
+                                    Slog.v(
+                                            TAG,
+                                            "current value is empty, using cached last "
+                                                    + "non-empty value instead");
                                 }
                                 currentValue = candidateSaveValue;
                             }
@@ -3897,8 +4280,14 @@
                         final AutofillValue filledValue = viewState.getAutofilledValue();
                         if (value != null && !value.equals(filledValue)) {
                             if (sDebug) {
-                                Slog.d(TAG, "found a change on optional " + id + ": " + filledValue
-                                        + " => " + value);
+                                Slog.d(
+                                        TAG,
+                                        "found a change on optional "
+                                                + id
+                                                + ": "
+                                                + filledValue
+                                                + " => "
+                                                + value);
                             }
                             if (filledValue != null) {
                                 isUpdate = true;
@@ -3907,12 +4296,16 @@
                             }
                             atLeastOneChanged = true;
                         }
-                    } else  {
+                    } else {
                         // Update current values cache based on initial value
                         final AutofillValue initialValue = getValueFromContextsLocked(id);
                         if (sDebug) {
-                            Slog.d(TAG, "no current value for " + id + "; initial value is "
-                                    + initialValue);
+                            Slog.d(
+                                    TAG,
+                                    "no current value for "
+                                            + id
+                                            + "; initial value is "
+                                            + initialValue);
                         }
                         if (initialValue != null) {
                             currentValues.put(id, initialValue);
@@ -3935,17 +4328,18 @@
                     try {
                         isValid = validator.isValid(this);
                         if (sDebug) Slog.d(TAG, validator + " returned " + isValid);
-                        log.setType(isValid
-                                ? MetricsEvent.TYPE_SUCCESS
-                                : MetricsEvent.TYPE_DISMISS);
+                        log.setType(
+                                isValid ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_DISMISS);
                     } catch (Exception e) {
                         Slog.e(TAG, "Not showing save UI because validation failed:", e);
                         log.setType(MetricsEvent.TYPE_FAILURE);
                         mMetricsLogger.write(log);
                         mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                            NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
+                                NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
                         mSaveEventLogger.logAndEndEvent();
-                        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                        return new SaveResult(
+                                /* logSaveShown= */ false,
+                                /* removeSession= */ true,
                                 Event.NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
                     }
 
@@ -3953,9 +4347,11 @@
                     if (!isValid) {
                         Slog.i(TAG, "not showing save UI because fields failed validation");
                         mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                            NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
+                                NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
                         mSaveEventLogger.logAndEndEvent();
-                        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                        return new SaveResult(
+                                /* logSaveShown= */ false,
+                                /* removeSession= */ true,
                                 Event.NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
                     }
                 }
@@ -3964,15 +4360,23 @@
                 // content.
                 final List<Dataset> datasets = response.getDatasets();
                 if (datasets != null) {
-                    datasets_loop: for (int i = 0; i < datasets.size(); i++) {
+                    datasets_loop:
+                    for (int i = 0; i < datasets.size(); i++) {
                         final Dataset dataset = datasets.get(i);
                         final ArrayMap<AutofillId, AutofillValue> datasetValues =
                                 Helper.getFields(dataset);
                         if (sVerbose) {
-                            Slog.v(TAG, "Checking if saved fields match contents of dataset #" + i
-                                    + ": " + dataset + "; savableIds=" + savableIds);
+                            Slog.v(
+                                    TAG,
+                                    "Checking if saved fields match contents of dataset #"
+                                            + i
+                                            + ": "
+                                            + dataset
+                                            + "; savableIds="
+                                            + savableIds);
                         }
-                        savable_ids_loop: for (int j = 0; j < savableIds.size(); j++) {
+                        savable_ids_loop:
+                        for (int j = 0; j < savableIds.size(); j++) {
                             final AutofillId id = savableIds.valueAt(j);
                             final AutofillValue currentValue = currentValues.get(id);
                             if (currentValue == null) {
@@ -3984,20 +4388,33 @@
                             final AutofillValue datasetValue = datasetValues.get(id);
                             if (!currentValue.equals(datasetValue)) {
                                 if (sDebug) {
-                                    Slog.d(TAG, "found a dataset change on id " + id + ": from "
-                                            + datasetValue + " to " + currentValue);
+                                    Slog.d(
+                                            TAG,
+                                            "found a dataset change on id "
+                                                    + id
+                                                    + ": from "
+                                                    + datasetValue
+                                                    + " to "
+                                                    + currentValue);
                                 }
                                 continue datasets_loop;
                             }
                             if (sVerbose) Slog.v(TAG, "no dataset changes for id " + id);
                         }
                         if (sDebug) {
-                            Slog.d(TAG, "ignoring Save UI because all fields match contents of "
-                                    + "dataset #" + i + ": " + dataset);
+                            Slog.d(
+                                    TAG,
+                                    "ignoring Save UI because all fields match contents of "
+                                            + "dataset #"
+                                            + i
+                                            + ": "
+                                            + dataset);
                         }
                         mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_DATASET_MATCH);
                         mSaveEventLogger.logAndEndEvent();
-                        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                        return new SaveResult(
+                                /* logSaveShown= */ false,
+                                /* removeSession= */ true,
                                 Event.NO_SAVE_UI_REASON_DATASET_MATCH);
                     }
                 }
@@ -4015,13 +4432,26 @@
                     wtf(null, "showSaveLocked(): no service label or icon");
                     mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NONE);
                     mSaveEventLogger.logAndEndEvent();
-                    return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                    return new SaveResult(
+                            /* logSaveShown= */ false,
+                            /* removeSession= */ true,
                             Event.NO_SAVE_UI_REASON_NONE);
                 }
-                getUiForShowing().showSaveUi(serviceLabel, serviceIcon,
-                        mService.getServicePackageName(), saveInfo, this,
-                        mComponentName, this, mContext,  mPendingSaveUi, isUpdate, mCompatMode,
-                        response.getShowSaveDialogIcon(), mSaveEventLogger);
+                getUiForShowing()
+                        .showSaveUi(
+                                serviceLabel,
+                                serviceIcon,
+                                mService.getServicePackageName(),
+                                saveInfo,
+                                this,
+                                mComponentName,
+                                this,
+                                mContext,
+                                mPendingSaveUi,
+                                isUpdate,
+                                mCompatMode,
+                                response.getShowSaveDialogIcon(),
+                                mSaveEventLogger);
                 if (client != null) {
                     try {
                         client.setSaveUiState(id, true);
@@ -4031,21 +4461,30 @@
                 }
                 mSessionFlags.mShowingSaveUi = true;
                 if (sDebug) {
-                    Slog.d(TAG, "Good news, everyone! All checks passed, show save UI for "
-                            + id + "!");
+                    Slog.d(
+                            TAG,
+                            "Good news, everyone! All checks passed, show save UI for " + id + "!");
                 }
-                return new SaveResult(/* logSaveShown= */ true, /* removeSession= */ false,
+                return new SaveResult(
+                        /* logSaveShown= */ true,
+                        /* removeSession= */ false,
                         Event.NO_SAVE_UI_REASON_NONE);
             }
         }
         // Nothing changed...
         if (sDebug) {
-            Slog.d(TAG, "showSaveLocked(" + id +"): with no changes, comes no responsibilities."
-                    + "allRequiredAreNotNull=" + allRequiredAreNotEmpty
-                    + ", atLeastOneChanged=" + atLeastOneChanged);
+            Slog.d(
+                    TAG,
+                    "showSaveLocked("
+                            + id
+                            + "): with no changes, comes no responsibilities."
+                            + "allRequiredAreNotNull="
+                            + allRequiredAreNotEmpty
+                            + ", atLeastOneChanged="
+                            + atLeastOneChanged);
         }
-        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
-                saveDialogNotShowReason);
+        return new SaveResult(
+                /* logSaveShown= */ false, /* removeSession= */ true, saveDialogNotShowReason);
     }
 
     private void logSaveShown() {
@@ -4078,25 +4517,21 @@
         return sanitized;
     }
 
-    /**
-     * Returns whether the session is currently showing the save UI
-     */
+    /** Returns whether the session is currently showing the save UI */
     @GuardedBy("mLock")
     boolean isSaveUiShowingLocked() {
         return mSessionFlags.mShowingSaveUi;
     }
 
-    /**
-     * Gets the latest non-empty value for the given id in the autofill contexts.
-     */
+    /** Gets the latest non-empty value for the given id in the autofill contexts. */
     @GuardedBy("mLock")
     @Nullable
     private ViewNode getViewNodeFromContextsLocked(@NonNull AutofillId autofillId) {
         final int numContexts = mContexts.size();
         for (int i = numContexts - 1; i >= 0; i--) {
             final FillContext context = mContexts.get(i);
-            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
-                    autofillId);
+            final ViewNode node =
+                    Helper.findViewNodeByAutofillId(context.getStructure(), autofillId);
             if (node != null) {
                 return node;
             }
@@ -4104,22 +4539,28 @@
         return null;
     }
 
-    /**
-     * Gets the latest non-empty value for the given id in the autofill contexts.
-     */
+    /** Gets the latest non-empty value for the given id in the autofill contexts. */
     @GuardedBy("mLock")
     @Nullable
     private AutofillValue getValueFromContextsLocked(@NonNull AutofillId autofillId) {
         final int numContexts = mContexts.size();
         for (int i = numContexts - 1; i >= 0; i--) {
             final FillContext context = mContexts.get(i);
-            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
-                    autofillId);
+            final ViewNode node =
+                    Helper.findViewNodeByAutofillId(context.getStructure(), autofillId);
             if (node != null) {
                 final AutofillValue value = node.getAutofillValue();
                 if (sDebug) {
-                    Slog.d(TAG, "getValueFromContexts(" + this.id + "/" + autofillId + ") at "
-                            + i + ": " + value);
+                    Slog.d(
+                            TAG,
+                            "getValueFromContexts("
+                                    + this.id
+                                    + "/"
+                                    + autofillId
+                                    + ") at "
+                                    + i
+                                    + ": "
+                                    + value);
                 }
                 if (value != null && !value.isEmpty()) {
                     return value;
@@ -4129,17 +4570,15 @@
         return null;
     }
 
-    /**
-     * Gets the latest autofill options for the given id in the autofill contexts.
-     */
+    /** Gets the latest autofill options for the given id in the autofill contexts. */
     @GuardedBy("mLock")
     @Nullable
     private CharSequence[] getAutofillOptionsFromContextsLocked(@NonNull AutofillId autofillId) {
         final int numContexts = mContexts.size();
         for (int i = numContexts - 1; i >= 0; i--) {
             final FillContext context = mContexts.get(i);
-            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
-                    autofillId);
+            final ViewNode node =
+                    Helper.findViewNodeByAutofillId(context.getStructure(), autofillId);
             if (node != null && node.getAutofillOptions() != null) {
                 return node.getAutofillOptions();
             }
@@ -4160,7 +4599,7 @@
             final FillContext context = mContexts.get(contextNum);
 
             final ViewNode[] nodes =
-                context.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
+                    context.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
 
             if (sVerbose) Slog.v(TAG, "updateValuesForSaveLocked(): updating " + context);
 
@@ -4191,8 +4630,11 @@
                 if (sanitizedValue != null) {
                     node.updateAutofillValue(sanitizedValue);
                 } else if (sDebug) {
-                    Slog.d(TAG, "updateValuesForSaveLocked(): not updating field " + id
-                            + " because it failed sanitization");
+                    Slog.d(
+                            TAG,
+                            "updateValuesForSaveLocked(): not updating field "
+                                    + id
+                                    + " because it failed sanitization");
                 }
             }
 
@@ -4200,28 +4642,33 @@
             context.getStructure().sanitizeForParceling(false);
 
             if (sVerbose) {
-                Slog.v(TAG, "updateValuesForSaveLocked(): dumping structure of " + context
-                        + " before calling service.save()");
+                Slog.v(
+                        TAG,
+                        "updateValuesForSaveLocked(): dumping structure of "
+                                + context
+                                + " before calling service.save()");
                 context.getStructure().dump(false);
             }
         }
     }
 
-    /**
-     * Calls service when user requested save.
-     */
+    /** Calls service when user requested save. */
     @GuardedBy("mLock")
     void callSaveLocked() {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#callSaveLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#callSaveLocked() rejected - session: " + id + " destroyed");
             mSaveEventLogger.maybeSetIsSaved(false);
             mSaveEventLogger.logAndEndEvent();
             return;
         }
         if (mRemoteFillService == null) {
-            wtf(null, "callSaveLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+            wtf(
+                    null,
+                    "callSaveLocked() called without a remote service. "
+                            + "mForAugmentedAutofillOnly: %s",
+                    mSessionFlags.mAugmentedAutofillOnly);
             mSaveEventLogger.maybeSetIsSaved(false);
             mSaveEventLogger.logAndEndEvent();
             return;
@@ -4241,7 +4688,7 @@
         // Remove pending fill requests as the session is finished.
         cancelCurrentRequestLocked();
 
-        final ArrayList<FillContext> contexts = mergePreviousSessionLocked( /* forSave= */ true);
+        final ArrayList<FillContext> contexts = mergePreviousSessionLocked(/* forSave= */ true);
 
         FieldClassificationResponse fieldClassificationResponse =
                 mClassificationState.mLastFieldClassificationResponse;
@@ -4251,8 +4698,9 @@
             if (mClientState == null) {
                 mClientState = new Bundle();
             }
-            mClientState.putParcelableArrayList(EXTRA_KEY_DETECTIONS, new ArrayList<>(
-                    fieldClassificationResponse.getClassifications()));
+            mClientState.putParcelableArrayList(
+                    EXTRA_KEY_DETECTIONS,
+                    new ArrayList<>(fieldClassificationResponse.getClassifications()));
         }
         final SaveRequest saveRequest =
                 new SaveRequest(contexts, mClientState, mSelectedDatasetIds);
@@ -4270,11 +4718,12 @@
      * from previous sessions that were asked by the service to be delayed (if any).
      *
      * <p>As a side-effect:
+     *
      * <ul>
-     *   <li>If the current {@link #mClientState} is {@code null}, sets it with the last non-
-     *   {@code null} client state from previous sessions.
+     *   <li>If the current {@link #mClientState} is {@code null}, sets it with the last non- {@code
+     *       null} client state from previous sessions.
      *   <li>When {@code forSave} is {@code true}, calls {@link #updateValuesForSaveLocked()} in the
-     *   previous sessions.
+     *       previous sessions.
      * </ul>
      */
     @NonNull
@@ -4283,30 +4732,51 @@
         final ArrayList<FillContext> contexts;
         if (previousSessions != null) {
             if (sDebug) {
-                Slog.d(TAG, "mergeSessions(" + this.id + "): Merging the content of "
-                        + previousSessions.size() + " sessions for task " + taskId);
+                Slog.d(
+                        TAG,
+                        "mergeSessions("
+                                + this.id
+                                + "): Merging the content of "
+                                + previousSessions.size()
+                                + " sessions for task "
+                                + taskId);
             }
             contexts = new ArrayList<>();
             for (int i = 0; i < previousSessions.size(); i++) {
                 final Session previousSession = previousSessions.get(i);
                 final ArrayList<FillContext> previousContexts = previousSession.mContexts;
                 if (previousContexts == null) {
-                    Slog.w(TAG, "mergeSessions(" + this.id + "): Not merging null contexts from "
-                            + previousSession.id);
+                    Slog.w(
+                            TAG,
+                            "mergeSessions("
+                                    + this.id
+                                    + "): Not merging null contexts from "
+                                    + previousSession.id);
                     continue;
                 }
                 if (forSave) {
                     previousSession.updateValuesForSaveLocked();
                 }
                 if (sDebug) {
-                    Slog.d(TAG, "mergeSessions(" + this.id + "): adding " + previousContexts.size()
-                            + " context from previous session #" + previousSession.id);
+                    Slog.d(
+                            TAG,
+                            "mergeSessions("
+                                    + this.id
+                                    + "): adding "
+                                    + previousContexts.size()
+                                    + " context from previous session #"
+                                    + previousSession.id);
                 }
                 contexts.addAll(previousContexts);
                 if (mClientState == null && previousSession.mClientState != null) {
                     if (sDebug) {
-                        Slog.d(TAG, "mergeSessions(" + this.id + "): setting client state from "
-                                + "previous session" + previousSession.id);
+                        Slog.d(
+                                TAG,
+                                "mergeSessions("
+                                        + this.id
+                                        + "): setting client state from "
+                                        + "previous session"
+                                        + previousSession.id);
                     }
                     mClientState = previousSession.mClientState;
                 }
@@ -4351,8 +4821,12 @@
         // If it's not, then check if it should start a partition.
         if (shouldStartNewPartitionLocked(id, flags)) {
             if (sDebug) {
-                Slog.d(TAG, "Starting partition or augmented request for view id " + id + ": "
-                        + viewState.getStateAsString());
+                Slog.d(
+                        TAG,
+                        "Starting partition or augmented request for view id "
+                                + id
+                                + ": "
+                                + viewState.getStateAsString());
             }
             // Fix to always let standard autofill start.
             // Sometimes activity contain IMPORTANT_FOR_AUTOFILL_NO fields which marks session as
@@ -4363,8 +4837,12 @@
         }
 
         if (sVerbose) {
-            Slog.v(TAG, "Not starting new partition for view " + id + ": "
-                    + viewState.getStateAsString());
+            Slog.v(
+                    TAG,
+                    "Not starting new partition for view "
+                            + id
+                            + ": "
+                            + viewState.getStateAsString());
         }
         return Optional.empty();
     }
@@ -4373,17 +4851,17 @@
      * Determines if a new partition should be started for an id.
      *
      * @param id The id of the view that is entered
-     *
      * @return {@code true} if a new partition should be started
      */
     @GuardedBy("mLock")
     private boolean shouldStartNewPartitionLocked(@NonNull AutofillId id, int flags) {
         final ViewState currentView = mViewStates.get(id);
-        SparseArray<FillResponse> responses = shouldRequestSecondaryProvider(flags)
-                ? mSecondaryResponses : mResponses;
+        SparseArray<FillResponse> responses =
+                shouldRequestSecondaryProvider(flags) ? mSecondaryResponses : mResponses;
         if (responses == null) {
-            return currentView != null && (currentView.getState()
-                    & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) == 0;
+            return currentView != null
+                    && (currentView.getState() & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST)
+                            == 0;
         }
 
         if (mSessionFlags.mExpiredResponse) {
@@ -4395,8 +4873,14 @@
 
         final int numResponses = responses.size();
         if (numResponses >= AutofillManagerService.getPartitionMaxCount()) {
-            Slog.e(TAG, "Not starting a new partition on " + id + " because session " + this.id
-                    + " reached maximum of " + AutofillManagerService.getPartitionMaxCount());
+            Slog.e(
+                    TAG,
+                    "Not starting a new partition on "
+                            + id
+                            + " because session "
+                            + this.id
+                            + " reached maximum of "
+                            + AutofillManagerService.getPartitionMaxCount());
             return false;
         }
 
@@ -4437,8 +4921,7 @@
     }
 
     boolean shouldRequestSecondaryProvider(int flags) {
-        if (!mService.isAutofillCredmanIntegrationEnabled()
-                || mSecondaryProviderHandler == null) {
+        if (!mService.isAutofillCredmanIntegrationEnabled() || mSecondaryProviderHandler == null) {
             return false;
         }
         if (mIsPrimaryCredential) {
@@ -4452,8 +4935,8 @@
     // 'Session.this.mLock', which is the same as mLock.
     @SuppressWarnings("GuardedBy")
     @GuardedBy("mLock")
-    void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int action,
-            int flags) {
+    void updateLocked(
+            AutofillId id, Rect virtualBounds, AutofillValue value, int action, int flags) {
         if (mDestroyed) {
             Slog.w(TAG, "updateLocked(" + id + "):  rejected - session: destroyed");
             return;
@@ -4464,7 +4947,7 @@
                 Slog.d(TAG, "updateLocked(" + id + "): Set the response has expired.");
             }
             mPresentationStatsEventLogger.maybeSetNoPresentationEventReasonIfNoReasonExists(
-                        NOT_SHOWN_REASON_VIEW_CHANGED);
+                    NOT_SHOWN_REASON_VIEW_CHANGED);
             mPresentationStatsEventLogger.logAndEndEvent("ACTION_RESPONSE_EXPIRED");
             return;
         }
@@ -4474,23 +4957,35 @@
         if (sVerbose) {
             Slog.v(
                     TAG,
-                    "updateLocked(" + id + "): "
-                            + "id=" + this.id
-                            + ", action=" + actionAsString(action)
-                            + ", flags=" + flags
-                            + ", mCurrentViewId=" + mCurrentViewId
-                            + ", mExpiredResponse=" + mSessionFlags.mExpiredResponse
-                            + ", viewState=" + viewState);
+                    "updateLocked("
+                            + id
+                            + "): "
+                            + "id="
+                            + this.id
+                            + ", action="
+                            + actionAsString(action)
+                            + ", flags="
+                            + flags
+                            + ", mCurrentViewId="
+                            + mCurrentViewId
+                            + ", mExpiredResponse="
+                            + mSessionFlags.mExpiredResponse
+                            + ", viewState="
+                            + viewState);
         }
 
         if (viewState == null) {
-            if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
+            if (action == ACTION_START_SESSION
+                    || action == ACTION_VALUE_CHANGED
                     || action == ACTION_VIEW_ENTERED) {
                 if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
                 boolean isIgnored = isIgnoredLocked(id);
-                viewState = new ViewState(id, this,
-                        isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL,
-                        mIsPrimaryCredential);
+                viewState =
+                        new ViewState(
+                                id,
+                                this,
+                                isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL,
+                                mIsPrimaryCredential);
                 mViewStates.put(id, viewState);
 
                 // TODO(b/73648631): for optimization purposes, should also ignore if change is
@@ -4521,7 +5016,7 @@
             mSessionFlags.mScreenHasCredmanField = true;
         }
 
-        switch(action) {
+        switch (action) {
             case ACTION_START_SESSION:
                 // View is triggering autofill.
                 mCurrentViewId = viewState.id;
@@ -4545,14 +5040,14 @@
             case ACTION_VALUE_CHANGED:
                 if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
                     // Must cancel the session if the value of the URL bar changed
-                    final String currentUrl = mUrlBar == null ? null
-                            : mUrlBar.getText().toString().trim();
+                    final String currentUrl =
+                            mUrlBar == null ? null : mUrlBar.getText().toString().trim();
                     if (currentUrl == null) {
                         // Validation check - shouldn't happen.
                         wtf(null, "URL bar value changed, but current value is null");
                         return;
                     }
-                    if (value == null || ! value.isText()) {
+                    if (value == null || !value.isText()) {
                         // Validation check - shouldn't happen.
                         wtf(null, "URL bar value changed to null or non-text: %s", value);
                         return;
@@ -4567,8 +5062,10 @@
                         // are finished, as the URL bar changed callback is usually called before
                         // the virtual views become invisible.
                         if (sDebug) {
-                            Slog.d(TAG, "Ignoring change on URL because session will finish when "
-                                    + "views are gone");
+                            Slog.d(
+                                    TAG,
+                                    "Ignoring change on URL because session will finish when "
+                                            + "views are gone");
                         }
                         return;
                     }
@@ -4598,8 +5095,9 @@
                 // isSameViewEntered has some limitations, where it isn't considered same view when
                 // autofill suggestions pop up, user selects, and the focus lands back on the view.
                 // isSameViewAgain tries to overcome that situation.
-                final boolean isSameViewAgain = isSameViewEntered
-                        || Objects.equals(mCurrentViewId, mPreviousNonNullEnteredViewId);
+                final boolean isSameViewAgain =
+                        isSameViewEntered
+                                || Objects.equals(mCurrentViewId, mPreviousNonNullEnteredViewId);
                 if (mCurrentViewId != null) {
                     mPreviousNonNullEnteredViewId = mCurrentViewId;
                 }
@@ -4655,8 +5153,8 @@
                 // Trigger augmented autofill if applicable
                 if ((flags & FLAG_MANUAL_REQUEST) == 0) {
                     // Not a manual request
-                    if (mAugmentedAutofillableIds != null && mAugmentedAutofillableIds.contains(
-                            id)) {
+                    if (mAugmentedAutofillableIds != null
+                            && mAugmentedAutofillableIds.contains(id)) {
                         // Regular autofill handled the view and returned null response, but it
                         // triggered augmented autofill
                         if (!isSameViewEntered) {
@@ -4664,16 +5162,20 @@
                             triggerAugmentedAutofillLocked(flags);
                         } else {
                             if (sDebug) {
-                                Slog.d(TAG, "skip augmented autofill for same view: "
-                                        + "same view entered");
+                                Slog.d(
+                                        TAG,
+                                        "skip augmented autofill for same view: "
+                                                + "same view entered");
                             }
                         }
                         return;
                     } else if (mSessionFlags.mAugmentedAutofillOnly && isSameViewEntered) {
                         // Regular autofill is disabled.
                         if (sDebug) {
-                            Slog.d(TAG, "skip augmented autofill for same view: "
-                                    + "standard autofill disabled.");
+                            Slog.d(
+                                    TAG,
+                                    "skip augmented autofill for same view: "
+                                            + "standard autofill disabled.");
                         }
                         return;
                     }
@@ -4717,8 +5219,8 @@
                     // on the IME side if it arrives before the input view is finished on the IME.
                     mInlineSessionController.resetInlineFillUiLocked();
 
-                    if ((viewState.getState() &
-                            ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) != 0) {
+                    if ((viewState.getState() & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST)
+                            != 0) {
                         // View was exited before Inline Request sent back, do not set it to
                         // null yet to let onHandleAssistData finish processing
                     } else {
@@ -4728,7 +5230,7 @@
                     // It's not necessary that there's no more presentation for this view. It could
                     // be that the user chose some suggestion, in which case, view exits.
                     mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
-                                NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
+                            NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
                 }
                 break;
             default:
@@ -4737,8 +5239,8 @@
     }
 
     @GuardedBy("mLock")
-    private void logPresentationStatsOnViewEnteredLocked(FillResponse response,
-            boolean isCredmanRequested) {
+    private void logPresentationStatsOnViewEnteredLocked(
+            FillResponse response, boolean isCredmanRequested) {
         mPresentationStatsEventLogger.maybeSetIsCredentialRequest(isCredmanRequested);
         mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
                 mFieldClassificationIdSnapshot);
@@ -4754,16 +5256,13 @@
 
     @GuardedBy("mLock")
     private void hideAugmentedAutofillLocked(@NonNull ViewState viewState) {
-        if ((viewState.getState()
-                & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
+        if ((viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
             viewState.resetState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
             cancelAugmentedAutofillLocked();
         }
     }
 
-    /**
-     * Checks whether a view should be ignored.
-     */
+    /** Checks whether a view should be ignored. */
     @GuardedBy("mLock")
     private boolean isIgnoredLocked(AutofillId id) {
         // Always check the latest response only
@@ -4782,22 +5281,30 @@
                 && getSaveInfoLocked() != null) {
             final int length = viewState.getCurrentValue().getTextValue().length();
             if (sDebug) {
-                Slog.d(TAG, "updateLocked(" + id + "): resetting value that was "
-                        + length + " chars long");
+                Slog.d(
+                        TAG,
+                        "updateLocked("
+                                + id
+                                + "): resetting value that was "
+                                + length
+                                + " chars long");
             }
-            final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_VALUE_RESET)
-                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_PREVIOUS_LENGTH, length);
+            final LogMaker log =
+                    newLogMaker(MetricsEvent.AUTOFILL_VALUE_RESET)
+                            .addTaggedData(MetricsEvent.FIELD_AUTOFILL_PREVIOUS_LENGTH, length);
             mMetricsLogger.write(log);
         }
     }
 
     @GuardedBy("mLock")
-    private void updateViewStateAndUiOnValueChangedLocked(AutofillId id, AutofillValue value,
-            ViewState viewState, int flags) {
+    private void updateViewStateAndUiOnValueChangedLocked(
+            AutofillId id, AutofillValue value, ViewState viewState, int flags) {
         // Cache the last non-empty value for save purpose. Some apps clear the form before
         // navigating to other activities.
-        if (mIgnoreViewStateResetToEmpty && (value == null || value.isEmpty())
-                && viewState.getCurrentValue() != null && viewState.getCurrentValue().isText()
+        if (mIgnoreViewStateResetToEmpty
+                && (value == null || value.isEmpty())
+                && viewState.getCurrentValue() != null
+                && viewState.getCurrentValue().isText()
                 && viewState.getCurrentValue().getTextValue() != null
                 && viewState.getCurrentValue().getTextValue().length() > 1) {
             if (sVerbose) {
@@ -4875,8 +5382,8 @@
      * indicate the IME attempting to probe the potentially sensitive content of inline suggestions.
      */
     @GuardedBy("mLock")
-    private void updateFilteringStateOnValueChangedLocked(@Nullable String newTextValue,
-            ViewState viewState) {
+    private void updateFilteringStateOnValueChangedLocked(
+            @Nullable String newTextValue, ViewState viewState) {
         if (newTextValue == null) {
             // Don't just return here, otherwise the IME can circumvent this logic using non-text
             // values.
@@ -4901,18 +5408,22 @@
     }
 
     @Override
-    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
-            @Nullable AutofillValue value, int flags) {
+    public void onFillReady(
+            @NonNull FillResponse response,
+            @NonNull AutofillId filledId,
+            @Nullable AutofillValue value,
+            int flags) {
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
                     mFieldClassificationIdSnapshot);
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillReady() rejected - session: " + id + " destroyed");
                 mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SESSION_DESTROYED);
                 mSaveEventLogger.logAndEndEvent();
                 mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
-                    NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY);
+                        NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY);
                 mPresentationStatsEventLogger.logAndEndEvent("on fill ready");
                 return;
             }
@@ -4954,7 +5465,6 @@
             } else {
                 setFillDialogDisabled();
             }
-
         }
 
         if (response.supportsInlineSuggestions()) {
@@ -4971,10 +5481,20 @@
             }
         }
 
-        getUiForShowing().showFillUi(filledId, response, filterText,
-                mService.getServicePackageName(), mComponentName,
-                serviceLabel, serviceIcon, this, mContext, id, mCompatMode,
-                mService.getMaster().getMaxInputLengthForAutofill());
+        getUiForShowing()
+                .showFillUi(
+                        filledId,
+                        response,
+                        filterText,
+                        mService.getServicePackageName(),
+                        mComponentName,
+                        serviceLabel,
+                        serviceIcon,
+                        this,
+                        mContext,
+                        id,
+                        mCompatMode,
+                        mService.getMaster().getMaxInputLengthForAutofill());
 
         synchronized (mLock) {
             if (mUiShownTime == 0) {
@@ -4983,21 +5503,26 @@
                 final long duration = mUiShownTime - mStartTime;
 
                 if (sDebug) {
-                    final StringBuilder msg = new StringBuilder("1st UI for ")
-                            .append(mActivityToken)
-                            .append(" shown in ");
+                    final StringBuilder msg =
+                            new StringBuilder("1st UI for ")
+                                    .append(mActivityToken)
+                                    .append(" shown in ");
                     TimeUtils.formatDuration(duration, msg);
                     Slog.d(TAG, msg.toString());
                 }
-                final StringBuilder historyLog = new StringBuilder("id=").append(id)
-                        .append(" app=").append(mActivityToken)
-                        .append(" svc=").append(mService.getServicePackageName())
-                        .append(" latency=");
+                final StringBuilder historyLog =
+                        new StringBuilder("id=")
+                                .append(id)
+                                .append(" app=")
+                                .append(mActivityToken)
+                                .append(" svc=")
+                                .append(mService.getServicePackageName())
+                                .append(" latency=");
                 TimeUtils.formatDuration(duration, historyLog);
                 mUiLatencyHistory.log(historyLog.toString());
 
-                addTaggedDataToRequestLogLocked(response.getRequestId(),
-                        MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
+                addTaggedDataToRequestLogLocked(
+                        response.getRequestId(), MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
             }
         }
     }
@@ -5052,8 +5577,8 @@
         }
     }
 
-    private boolean requestShowFillDialog(FillResponse response,
-            AutofillId filledId, String filterText, int flags) {
+    private boolean requestShowFillDialog(
+            FillResponse response, AutofillId filledId, String filterText, int flags) {
         if (!isFillDialogUiEnabled()) {
             // Unsupported fill dialog UI
             if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled");
@@ -5079,7 +5604,6 @@
                 if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed.");
                 return false;
             }
-
         }
 
         Drawable serviceIcon = null;
@@ -5087,21 +5611,31 @@
             serviceIcon = getServiceIcon(response);
         }
 
-        getUiForShowing().showFillDialog(filledId, response, filterText,
-                mService.getServicePackageName(), mComponentName, serviceIcon, this,
-                id, mCompatMode, mPresentationStatsEventLogger, mLock);
+        getUiForShowing()
+                .showFillDialog(
+                        filledId,
+                        response,
+                        filterText,
+                        mService.getServicePackageName(),
+                        mComponentName,
+                        serviceIcon,
+                        this,
+                        id,
+                        mCompatMode,
+                        mPresentationStatsEventLogger,
+                        mLock);
         return true;
     }
 
     /**
-     * Get the custom icon that was passed through FillResponse. If the custom icon wasn't able
-     * to be fetched, use the default provider icon instead
+     * Get the custom icon that was passed through FillResponse. If the custom icon wasn't able to
+     * be fetched, use the default provider icon instead
      *
      * @return Drawable of the provider icon, if it was able to be fetched. Null otherwise
      */
     @SuppressWarnings("GuardedBy") // ErrorProne says we need to use mService.mLock, but it's
-                                   // actually the same object as mLock.
-                                   // TODO: Expose mService.mLock or redesign instead.
+    // actually the same object as mLock.
+    // TODO: Expose mService.mLock or redesign instead.
     @GuardedBy("mLock")
     private Drawable getServiceIcon(FillResponse response) {
         Drawable serviceIcon = null;
@@ -5130,14 +5664,14 @@
     }
 
     /**
-     * Get the custom label that was passed through FillResponse. If the custom label
-     * wasn't able to be fetched, use the default provider icon instead
+     * Get the custom label that was passed through FillResponse. If the custom label wasn't able to
+     * be fetched, use the default provider icon instead
      *
      * @return Drawable of the provider icon, if it was able to be fetched. Null otherwise
      */
     @SuppressWarnings("GuardedBy") // ErrorProne says we need to use mService.mLock, but it's
-                                   // actually the same object as mLock.
-                                   // TODO: Expose mService.mLock or redesign instead.
+    // actually the same object as mLock.
+    // TODO: Expose mService.mLock or redesign instead.
     @GuardedBy("mLock")
     private CharSequence getServiceLabel(FillResponse response) {
         CharSequence serviceLabel = null;
@@ -5167,11 +5701,9 @@
         return serviceLabel;
     }
 
-    /**
-     * Returns whether we made a request to show inline suggestions.
-     */
-    private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response,
-            @Nullable String filterText) {
+    /** Returns whether we made a request to show inline suggestions. */
+    private boolean requestShowInlineSuggestionsLocked(
+            @NonNull FillResponse response, @Nullable String filterText) {
         if (mCurrentViewId == null) {
             Log.w(TAG, "requestShowInlineSuggestionsLocked(): no view currently focused");
             return false;
@@ -5199,89 +5731,122 @@
         }
 
         final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
-                new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
-                        filterText, remoteRenderService, userId, id);
-        InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
-                new InlineFillUi.InlineSuggestionUiCallback() {
-                    @Override
-                    public void autofill(@NonNull Dataset dataset, int datasetIndex) {
-                        fill(response.getRequestId(), datasetIndex, dataset, UI_TYPE_INLINE);
-                    }
+                new InlineFillUi.InlineFillUiInfo(
+                        inlineSuggestionsRequest.get(),
+                        focusedId,
+                        filterText,
+                        remoteRenderService,
+                        userId,
+                        id);
+        InlineFillUi inlineFillUi =
+                InlineFillUi.forAutofill(
+                        inlineFillUiInfo,
+                        response,
+                        new InlineFillUi.InlineSuggestionUiCallback() {
+                            @Override
+                            public void autofill(@NonNull Dataset dataset, int datasetIndex) {
+                                fill(
+                                        response.getRequestId(),
+                                        datasetIndex,
+                                        dataset,
+                                        UI_TYPE_INLINE);
+                            }
 
-                    @Override
-                    public void authenticate(int requestId, int datasetIndex) {
-                        Session.this.authenticate(response.getRequestId(), datasetIndex,
-                                response.getAuthentication(), response.getClientState(),
-                                UI_TYPE_INLINE);
-                    }
+                            @Override
+                            public void authenticate(int requestId, int datasetIndex) {
+                                Session.this.authenticate(
+                                        response.getRequestId(),
+                                        datasetIndex,
+                                        response.getAuthentication(),
+                                        response.getClientState(),
+                                        UI_TYPE_INLINE);
+                            }
 
-                    @Override
-                    public void startIntentSender(@NonNull IntentSender intentSender) {
-                        Session.this.startIntentSender(intentSender, new Intent());
-                    }
+                            @Override
+                            public void startIntentSender(@NonNull IntentSender intentSender) {
+                                Session.this.startIntentSender(intentSender, new Intent());
+                            }
 
-                    @Override
-                    public void onError() {
-                        synchronized (mLock) {
-                            mInlineSessionController.setInlineFillUiLocked(
-                                    InlineFillUi.emptyUi(focusedId));
-                        }
-                    }
+                            @Override
+                            public void onError() {
+                                synchronized (mLock) {
+                                    mInlineSessionController.setInlineFillUiLocked(
+                                            InlineFillUi.emptyUi(focusedId));
+                                }
+                            }
 
-                    @Override
-                    public void onInflate() {
-                        Session.this.onShown(UI_TYPE_INLINE, 1);
-                    }
-                }, mService.getMaster().getMaxInputLengthForAutofill());
+                            @Override
+                            public void onInflate() {
+                                Session.this.onShown(UI_TYPE_INLINE, 1);
+                            }
+                        },
+                        mService.getMaster().getMaxInputLengthForAutofill());
         return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
     }
 
     private ResultReceiver constructCredentialManagerCallback(int requestId) {
-        final ResultReceiver resultReceiver = new ResultReceiver(mHandler) {
-            final AutofillId mAutofillId = mCurrentViewId;
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
-                    Slog.d(TAG, "onReceiveResult from Credential Manager "
-                            + "bottom sheet with mCurrentViewId: " + mAutofillId);
-                    GetCredentialResponse getCredentialResponse =
-                            resultData.getParcelable(
-                                    CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
-                                    GetCredentialResponse.class);
+        final ResultReceiver resultReceiver =
+                new ResultReceiver(mHandler) {
+                    final AutofillId mAutofillId = mCurrentViewId;
 
-                    if (Flags.autofillCredmanDevIntegration()) {
-                        sendCredentialManagerResponseToApp(getCredentialResponse,
-                                /*exception=*/ null, mAutofillId);
-                    } else {
-                        Dataset datasetFromCredential = getDatasetFromCredentialResponse(
-                                getCredentialResponse);
-                        if (datasetFromCredential != null) {
-                            autoFill(requestId, /*datasetIndex=*/-1,
-                                    datasetFromCredential, false,
-                                    UI_TYPE_CREDMAN_BOTTOM_SHEET);
+                    @Override
+                    protected void onReceiveResult(int resultCode, Bundle resultData) {
+                        if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
+                            Slog.d(
+                                    TAG,
+                                    "onReceiveResult from Credential Manager "
+                                            + "bottom sheet with mCurrentViewId: "
+                                            + mAutofillId);
+                            GetCredentialResponse getCredentialResponse =
+                                    resultData.getParcelable(
+                                            CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
+                                            GetCredentialResponse.class);
+
+                            if (Flags.autofillCredmanDevIntegration()) {
+                                sendCredentialManagerResponseToApp(
+                                        getCredentialResponse, /* exception= */ null, mAutofillId);
+                            } else {
+                                Dataset datasetFromCredential =
+                                        getDatasetFromCredentialResponse(getCredentialResponse);
+                                if (datasetFromCredential != null) {
+                                    autoFill(
+                                            requestId,
+                                            /* datasetIndex= */ -1,
+                                            datasetFromCredential,
+                                            false,
+                                            UI_TYPE_CREDMAN_BOTTOM_SHEET);
+                                }
+                            }
+                        } else if (resultCode == FAILURE_CREDMAN_SELECTOR) {
+                            String[] exception =
+                                    resultData.getStringArray(
+                                            CredentialProviderService
+                                                    .EXTRA_GET_CREDENTIAL_EXCEPTION);
+                            if (exception != null && exception.length >= 2) {
+                                String errType = exception[0];
+                                String errMsg = exception[1];
+                                Slog.w(
+                                        TAG,
+                                        "Credman bottom sheet from pinned "
+                                                + "entry failed with: + "
+                                                + errType
+                                                + " , "
+                                                + errMsg);
+                                sendCredentialManagerResponseToApp(
+                                        /* response= */ null,
+                                        new GetCredentialException(errType, errMsg),
+                                        mAutofillId);
+                            }
+                        } else {
+                            Slog.d(
+                                    TAG,
+                                    "Unknown resultCode from credential "
+                                            + "manager bottom sheet: "
+                                            + resultCode);
                         }
                     }
-                } else if (resultCode == FAILURE_CREDMAN_SELECTOR) {
-                    String[] exception =  resultData.getStringArray(
-                            CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);
-                    if (exception != null && exception.length >= 2) {
-                        String errType = exception[0];
-                        String errMsg = exception[1];
-                        Slog.w(TAG, "Credman bottom sheet from pinned "
-                                + "entry failed with: + " + errType + " , "
-                                + errMsg);
-                        sendCredentialManagerResponseToApp(/*response=*/ null,
-                                new GetCredentialException(errType, errMsg),
-                                mAutofillId);
-                    }
-                } else {
-                    Slog.d(TAG, "Unknown resultCode from credential "
-                            + "manager bottom sheet: " + resultCode);
-                }
-            }
-        };
-        ResultReceiver ipcFriendlyResultReceiver =
-                toIpcFriendlyResultReceiver(resultReceiver);
+                };
+        ResultReceiver ipcFriendlyResultReceiver = toIpcFriendlyResultReceiver(resultReceiver);
 
         return ipcFriendlyResultReceiver;
     }
@@ -5309,8 +5874,8 @@
         }
     }
 
-    private void notifyUnavailableToClient(int sessionFinishedState,
-            @Nullable ArrayList<AutofillId> autofillableIds) {
+    private void notifyUnavailableToClient(
+            int sessionFinishedState, @Nullable ArrayList<AutofillId> autofillableIds) {
         synchronized (mLock) {
             if (mCurrentViewId == null) return;
             try {
@@ -5374,27 +5939,25 @@
                 if (saveInfo.getRequiredIds() != null) {
                     Collections.addAll(trackedViews, saveInfo.getRequiredIds());
                     mSaveEventLogger.maybeSetSaveUiShownReason(
-                        SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE);
+                            SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE);
                 }
 
                 if (saveInfo.getOptionalIds() != null) {
                     Collections.addAll(trackedViews, saveInfo.getOptionalIds());
                     mSaveEventLogger.maybeSetSaveUiShownReason(
-                        SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE);
+                            SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE);
                 }
             }
             if ((flags & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
-                mSaveEventLogger.maybeSetSaveUiShownReason(
-                    SAVE_UI_SHOWN_REASON_UNKNOWN);
+                mSaveEventLogger.maybeSetSaveUiShownReason(SAVE_UI_SHOWN_REASON_UNKNOWN);
                 mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                    NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG);
+                        NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG);
                 saveOnFinish = false;
             }
 
         } else {
             flags = 0;
-            mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                NO_SAVE_REASON_NO_SAVE_INFO);
+            mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NO_SAVE_INFO);
             saveTriggerId = null;
         }
 
@@ -5427,21 +5990,35 @@
 
         try {
             if (sVerbose) {
-                Slog.v(TAG, "updateTrackedIdsLocked(): trackedViews: " + trackedViews
-                        + " fillableIds: " + fillableIds + " triggerId: " + saveTriggerId
-                        + " saveOnFinish:" + saveOnFinish + " flags: " + flags
-                        + " hasSaveInfo: " + (saveInfo != null));
+                Slog.v(
+                        TAG,
+                        "updateTrackedIdsLocked(): trackedViews: "
+                                + trackedViews
+                                + " fillableIds: "
+                                + fillableIds
+                                + " triggerId: "
+                                + saveTriggerId
+                                + " saveOnFinish:"
+                                + saveOnFinish
+                                + " flags: "
+                                + flags
+                                + " hasSaveInfo: "
+                                + (saveInfo != null));
             }
-            mClient.setTrackedViews(id, toArray(trackedViews), mSaveOnAllViewsInvisible,
-                    saveOnFinish, toArray(fillableIds), saveTriggerId, hasAuthentication);
+            mClient.setTrackedViews(
+                    id,
+                    toArray(trackedViews),
+                    mSaveOnAllViewsInvisible,
+                    saveOnFinish,
+                    toArray(fillableIds),
+                    saveTriggerId,
+                    hasAuthentication);
         } catch (RemoteException e) {
             Slog.w(TAG, "Cannot set tracked ids", e);
         }
     }
 
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+    /** Sets the state of views that failed to autofill. */
     @GuardedBy("mLock")
     void setAutofillFailureLocked(@NonNull List<AutofillId> ids, boolean isRefill) {
         if (sVerbose && !ids.isEmpty()) {
@@ -5464,9 +6041,7 @@
         mPresentationStatsEventLogger.maybeSetViewFillFailureCounts(ids, isRefill);
     }
 
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+    /** Sets the state of views that failed to autofill. */
     @GuardedBy("mLock")
     void setViewAutofilledLocked(@NonNull AutofillId id) {
         if (sVerbose) {
@@ -5478,17 +6053,14 @@
         mPresentationStatsEventLogger.maybeAddSuccessId(id);
     }
 
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+    /** Sets the state of views that failed to autofill. */
     void setNotifyNotExpiringResponseDuringAuth() {
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetNotifyNotExpiringResponseDuringAuth();
         }
     }
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+
+    /** Sets the state of views that failed to autofill. */
     void setLogViewEnteredIgnoredDuringAuth() {
         synchronized (mLock) {
             mPresentationStatsEventLogger.notifyViewEnteredIgnoredDuringAuthCount();
@@ -5496,10 +6068,15 @@
     }
 
     @GuardedBy("mLock")
-    private void replaceResponseLocked(@NonNull FillResponse oldResponse,
-            @NonNull FillResponse newResponse, @Nullable Bundle newClientState) {
+    private void replaceResponseLocked(
+            @NonNull FillResponse oldResponse,
+            @NonNull FillResponse newResponse,
+            @Nullable Bundle newClientState) {
         // Disassociate view states with the old response
-        setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, /* clearResponse= */ true,
+        setViewStatesLocked(
+                oldResponse,
+                ViewState.STATE_INITIAL,
+                /* clearResponse= */ true,
                 /* isPrimary= */ true);
         // Move over the id
         newResponse.setRequestId(oldResponse.getRequestId());
@@ -5519,7 +6096,7 @@
         final ArrayList<AutofillId> autofillableIds;
         if (context != null) {
             final AssistStructure structure = context.getStructure();
-            autofillableIds = Helper.getAutofillIds(structure, /* autofillableOnly= */true);
+            autofillableIds = Helper.getAutofillIds(structure, /* autofillableOnly= */ true);
         } else {
             Slog.w(TAG, "processNullResponseLocked(): no context for req " + requestId);
             autofillableIds = null;
@@ -5535,8 +6112,13 @@
         mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked(flags);
         if (mAugmentedAutofillDestroyer == null && ((flags & FLAG_PASSWORD_INPUT_TYPE) == 0)) {
             if (sVerbose) {
-                Slog.v(TAG, "canceling session " + id + " when service returned null and it cannot "
-                        + "be augmented. AutofillableIds: " + autofillableIds);
+                Slog.v(
+                        TAG,
+                        "canceling session "
+                                + id
+                                + " when service returned null and it cannot "
+                                + "be augmented. AutofillableIds: "
+                                + autofillableIds);
             }
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
@@ -5544,15 +6126,25 @@
         } else {
             if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
                 if (sVerbose) {
-                    Slog.v(TAG, "keeping session " + id + " when service returned null and "
-                            + "augmented service is disabled for password fields. "
-                            + "AutofillableIds: " + autofillableIds);
+                    Slog.v(
+                            TAG,
+                            "keeping session "
+                                    + id
+                                    + " when service returned null and "
+                                    + "augmented service is disabled for password fields. "
+                                    + "AutofillableIds: "
+                                    + autofillableIds);
                 }
                 mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
             } else {
                 if (sVerbose) {
-                    Slog.v(TAG, "keeping session " + id + " when service returned null but "
-                            + "it can be augmented. AutofillableIds: " + autofillableIds);
+                    Slog.v(
+                            TAG,
+                            "keeping session "
+                                    + id
+                                    + " when service returned null but "
+                                    + "it can be augmented. AutofillableIds: "
+                                    + autofillableIds);
                 }
             }
             mAugmentedAutofillableIds = autofillableIds;
@@ -5567,8 +6159,8 @@
     /**
      * Tries to trigger Augmented Autofill when the standard service could not fulfill a request.
      *
-     * <p> The request may not have been sent when this method returns as it may be waiting for
-     * the inline suggestion request asynchronously.
+     * <p>The request may not have been sent when this method returns as it may be waiting for the
+     * inline suggestion request asynchronously.
      *
      * @return callback to destroy the autofill UI, or {@code null} if not supported.
      */
@@ -5582,8 +6174,8 @@
         }
 
         // Check if Smart Suggestions is supported...
-        final @SmartSuggestionMode int supportedModes = mService
-                .getSupportedSmartSuggestionModesLocked();
+        final @SmartSuggestionMode int supportedModes =
+                mService.getSupportedSmartSuggestionModesLocked();
         if (supportedModes == 0) {
             if (sVerbose) Slog.v(TAG, "triggerAugmentedAutofillLocked(): no supported modes");
             return null;
@@ -5591,8 +6183,8 @@
 
         // ...then if the service is set for the user
 
-        final RemoteAugmentedAutofillService remoteService = mService
-                .getRemoteAugmentedAutofillServiceLocked();
+        final RemoteAugmentedAutofillService remoteService =
+                mService.getRemoteAugmentedAutofillServiceLocked();
         if (remoteService == null) {
             if (sVerbose) Slog.v(TAG, "triggerAugmentedAutofillLocked(): no service for user");
             return null;
@@ -5612,25 +6204,37 @@
             return null;
         }
 
-        final boolean isAllowlisted = mService
-                .isWhitelistedForAugmentedAutofillLocked(mComponentName);
+        final boolean isAllowlisted =
+                mService.isWhitelistedForAugmentedAutofillLocked(mComponentName);
 
         if (!isAllowlisted) {
             if (sVerbose) {
-                Slog.v(TAG, "triggerAugmentedAutofillLocked(): "
-                        + ComponentName.flattenToShortString(mComponentName) + " not whitelisted ");
+                Slog.v(
+                        TAG,
+                        "triggerAugmentedAutofillLocked(): "
+                                + ComponentName.flattenToShortString(mComponentName)
+                                + " not whitelisted ");
             }
-            logAugmentedAutofillRequestLocked(mode, remoteService.getComponentName(),
-                    mCurrentViewId, isAllowlisted, /* isInline= */ null);
+            logAugmentedAutofillRequestLocked(
+                    mode,
+                    remoteService.getComponentName(),
+                    mCurrentViewId,
+                    isAllowlisted,
+                    /* isInline= */ null);
             return null;
         }
 
         if (sVerbose) {
-            Slog.v(TAG, "calling Augmented Autofill Service ("
-                    + ComponentName.flattenToShortString(remoteService.getComponentName())
-                    + ") on view " + mCurrentViewId + " using suggestion mode "
-                    + getSmartSuggestionModeToString(mode)
-                    + " when server returned null for session " + this.id);
+            Slog.v(
+                    TAG,
+                    "calling Augmented Autofill Service ("
+                            + ComponentName.flattenToShortString(remoteService.getComponentName())
+                            + ") on view "
+                            + mCurrentViewId
+                            + " using suggestion mode "
+                            + getSmartSuggestionModeToString(mode)
+                            + " when server returned null for session "
+                            + this.id);
         }
         // Log FillRequest for Augmented Autofill.
         mFillRequestEventLogger.startLogForNewRequest();
@@ -5648,8 +6252,10 @@
         if (mAugmentedRequestsLogs == null) {
             mAugmentedRequestsLogs = new ArrayList<>();
         }
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_AUGMENTED_REQUEST,
-                remoteService.getComponentName().getPackageName());
+        final LogMaker log =
+                newLogMaker(
+                        MetricsEvent.AUTOFILL_AUGMENTED_REQUEST,
+                        remoteService.getComponentName().getPackageName());
         mAugmentedRequestsLogs.add(log);
 
         final AutofillId focusedId = mCurrentViewId;
@@ -5715,8 +6321,7 @@
             }
             synchronized (session.mLock) {
                 session.mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
-                        mFocusedId, /*requestConsumer=*/ mRequestAugmentedAutofill,
-                        result);
+                        mFocusedId, /* requestConsumer= */ mRequestAugmentedAutofill, result);
             }
         }
     }
@@ -5741,19 +6346,17 @@
             mIsAllowlisted = isAllowlisted;
             mMode = mode;
             mCurrentValue = currentValue;
-
         }
+
         @Override
         public void accept(InlineSuggestionsRequest inlineSuggestionsRequest) {
             Session session = mSessionWeakRef.get();
 
-            if (logIfSessionNull(
-                    session, "AugmentedAutofillInlineSuggestionRequestConsumer:")) {
+            if (logIfSessionNull(session, "AugmentedAutofillInlineSuggestionRequestConsumer:")) {
                 return;
             }
             session.onAugmentedAutofillInlineSuggestionAccept(
                     inlineSuggestionsRequest, mFocusedId, mIsAllowlisted, mMode, mCurrentValue);
-
         }
     }
 
@@ -5770,8 +6373,7 @@
         public Boolean apply(InlineFillUi inlineFillUi) {
             Session session = mSessionWeakRef.get();
 
-            if (logIfSessionNull(
-                    session, "AugmentedAutofillInlineSuggestionsResponseCallback:")) {
+            if (logIfSessionNull(session, "AugmentedAutofillInlineSuggestionsResponseCallback:")) {
                 return false;
             }
 
@@ -5801,8 +6403,9 @@
     }
 
     /**
-     * If the session is null or has been destroyed, log the error msg, and return true.
-     * This is a helper function intended to be called when de-referencing from a weak reference.
+     * If the session is null or has been destroyed, log the error msg, and return true. This is a
+     * helper function intended to be called when de-referencing from a weak reference.
+     *
      * @param session
      * @param logPrefix
      * @return true if the session is null, false otherwise.
@@ -5830,15 +6433,25 @@
         synchronized (mLock) {
             final RemoteAugmentedAutofillService remoteService =
                     mService.getRemoteAugmentedAutofillServiceLocked();
-            logAugmentedAutofillRequestLocked(mode, remoteService.getComponentName(),
-                    focussedId, isAllowlisted, inlineSuggestionsRequest != null);
-            remoteService.onRequestAutofillLocked(id, mClient,
-                    taskId, mComponentName, mActivityToken,
-                    AutofillId.withoutSession(focussedId), currentValue,
+            logAugmentedAutofillRequestLocked(
+                    mode,
+                    remoteService.getComponentName(),
+                    focussedId,
+                    isAllowlisted,
+                    inlineSuggestionsRequest != null);
+            remoteService.onRequestAutofillLocked(
+                    id,
+                    mClient,
+                    taskId,
+                    mComponentName,
+                    mActivityToken,
+                    AutofillId.withoutSession(focussedId),
+                    currentValue,
                     inlineSuggestionsRequest,
                     new AugmentedAutofillInlineSuggestionsResponseCallback(this),
                     new AugmentedAutofillErrorCallback(this),
-                    mService.getRemoteInlineSuggestionRenderServiceLocked(), userId);
+                    mService.getRemoteInlineSuggestionRenderServiceLocked(),
+                    userId);
         }
     }
 
@@ -5847,15 +6460,14 @@
             cancelAugmentedAutofillLocked();
 
             // Also cancel augmented in IME
-            mInlineSessionController.setInlineFillUiLocked(
-                    InlineFillUi.emptyUi(mCurrentViewId));
+            mInlineSessionController.setInlineFillUiLocked(InlineFillUi.emptyUi(mCurrentViewId));
         }
     }
 
     @GuardedBy("mLock")
     private void cancelAugmentedAutofillLocked() {
-        final RemoteAugmentedAutofillService remoteService = mService
-                .getRemoteAugmentedAutofillServiceLocked();
+        final RemoteAugmentedAutofillService remoteService =
+                mService.getRemoteAugmentedAutofillServiceLocked();
         if (remoteService == null) {
             Slog.w(TAG, "cancelAugmentedAutofillLocked(): no service for user");
             return;
@@ -5865,8 +6477,8 @@
     }
 
     @GuardedBy("mLock")
-    private void processResponseLocked(@NonNull FillResponse newResponse,
-            @Nullable Bundle newClientState, int flags) {
+    private void processResponseLocked(
+            @NonNull FillResponse newResponse, @Nullable Bundle newClientState, int flags) {
         // Make sure we are hiding the UI which will be shown
         // only if handling the current response requires it.
         mUi.hideAll(this);
@@ -5878,9 +6490,18 @@
 
         final int requestId = newResponse.getRequestId();
         if (sVerbose) {
-            Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId
-                    + ",flags=" + flags + ", reqId=" + requestId + ", resp=" + newResponse
-                    + ",newClientState=" + newClientState);
+            Slog.v(
+                    TAG,
+                    "processResponseLocked(): mCurrentViewId="
+                            + mCurrentViewId
+                            + ",flags="
+                            + flags
+                            + ", reqId="
+                            + requestId
+                            + ", resp="
+                            + newResponse
+                            + ",newClientState="
+                            + newClientState);
         }
 
         if (mResponses == null) {
@@ -5892,8 +6513,9 @@
         mResponses.put(requestId, newResponse);
         mClientState = newClientState != null ? newClientState : newResponse.getClientState();
 
-        boolean webviewRequestedCredman = newClientState != null && newClientState.getBoolean(
-                WEBVIEW_REQUESTED_CREDENTIAL_KEY, false);
+        boolean webviewRequestedCredman =
+                newClientState != null
+                        && newClientState.getBoolean(WEBVIEW_REQUESTED_CREDENTIAL_KEY, false);
         List<Dataset> datasetList = newResponse.getDatasets();
 
         mPresentationStatsEventLogger.maybeSetWebviewRequestedCredential(webviewRequestedCredman);
@@ -5901,7 +6523,10 @@
         mPresentationStatsEventLogger.maybeSetAvailableCount(datasetList, mCurrentViewId);
         mFillResponseEventLogger.maybeSetDatasetsCountAfterPotentialPccFiltering(datasetList);
 
-        setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, /* clearResponse= */ false,
+        setViewStatesLocked(
+                newResponse,
+                ViewState.STATE_FILLABLE,
+                /* clearResponse= */ false,
                 /* isPrimary= */ true);
         updateFillDialogTriggerIdsLocked();
         updateTrackedIdsLocked();
@@ -5914,12 +6539,10 @@
         currentView.maybeCallOnFillReady(flags);
     }
 
-    /**
-     * Sets the state of all views in the given response.
-     */
+    /** Sets the state of all views in the given response. */
     @GuardedBy("mLock")
-    private void setViewStatesLocked(FillResponse response, int state, boolean clearResponse,
-                                     boolean isPrimary) {
+    private void setViewStatesLocked(
+            FillResponse response, int state, boolean clearResponse, boolean isPrimary) {
         final List<Dataset> datasets = response.getDatasets();
         if (datasets != null && !datasets.isEmpty()) {
             for (int i = 0; i < datasets.size(); i++) {
@@ -5964,12 +6587,14 @@
         }
     }
 
-    /**
-     * Sets the state and response of all views in the given dataset.
-     */
+    /** Sets the state and response of all views in the given dataset. */
     @GuardedBy("mLock")
-    private void setViewStatesLocked(@Nullable FillResponse response, @NonNull Dataset dataset,
-            int state, boolean clearResponse, boolean isPrimary) {
+    private void setViewStatesLocked(
+            @Nullable FillResponse response,
+            @NonNull Dataset dataset,
+            int state,
+            boolean clearResponse,
+            boolean isPrimary) {
         final ArrayList<AutofillId> ids = dataset.getFieldIds();
         final ArrayList<AutofillValue> values = dataset.getFieldValues();
         for (int j = 0; j < ids.size(); j++) {
@@ -5989,10 +6614,10 @@
     }
 
     @GuardedBy("mLock")
-    private ViewState createOrUpdateViewStateLocked(@NonNull AutofillId id, int state,
-            @Nullable AutofillValue value) {
+    private ViewState createOrUpdateViewStateLocked(
+            @NonNull AutofillId id, int state, @Nullable AutofillValue value) {
         ViewState viewState = mViewStates.get(id);
-        if (viewState != null)  {
+        if (viewState != null) {
             viewState.setState(state);
         } else {
             viewState = new ViewState(id, this, state, mIsPrimaryCredential);
@@ -6008,22 +6633,27 @@
         return viewState;
     }
 
-    void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent,
-            int uiType) {
+    void autoFill(
+            int requestId, int datasetIndex, Dataset dataset, boolean generateEvent, int uiType) {
         if (sDebug) {
-            Slog.d(TAG, "autoFill(): requestId=" + requestId  + "; datasetIdx=" + datasetIndex
-                    + "; dataset=" + dataset);
+            Slog.d(
+                    TAG,
+                    "autoFill(): requestId="
+                            + requestId
+                            + "; datasetIdx="
+                            + datasetIndex
+                            + "; dataset="
+                            + dataset);
         }
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#autoFill() rejected - session: " + id + " destroyed");
                 return;
             }
             // Selected dataset id is logged regardless of authentication result.
             mPresentationStatsEventLogger.maybeSetSelectedDatasetId(datasetIndex);
             mPresentationStatsEventLogger.maybeSetSelectedDatasetPickReason(
-                dataset.getEligibleReason());
+                    dataset.getEligibleReason());
             // Autofill it directly...
             if (dataset.getAuthentication() == null) {
                 if (generateEvent) {
@@ -6039,10 +6669,14 @@
             // ...or handle authentication.
             mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType);
             mPresentationStatsEventLogger.maybeSetAuthenticationType(
-                AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
+                    AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
             // does not matter the value of isPrimary because null response won't be overridden.
-            setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH,
-                    /* clearResponse= */ false, /* isPrimary= */ true);
+            setViewStatesLocked(
+                    null,
+                    dataset,
+                    ViewState.STATE_WAITING_DATASET_AUTH,
+                    /* clearResponse= */ false,
+                    /* isPrimary= */ true);
             final Intent fillInIntent;
             if (dataset.getCredentialFillInIntent() != null && Flags.autofillCredmanIntegration()) {
                 Slog.d(TAG, "Setting credential fill intent");
@@ -6055,11 +6689,13 @@
                 forceRemoveFromServiceLocked();
                 return;
             }
-            final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
-                    datasetIndex);
-            startAuthentication(authenticationId, dataset.getAuthentication(), fillInIntent,
-                    /* authenticateInline= */false);
-
+            final int authenticationId =
+                    AutofillManager.makeAuthenticationId(requestId, datasetIndex);
+            startAuthentication(
+                    authenticationId,
+                    dataset.getAuthentication(),
+                    fillInIntent,
+                    /* authenticateInline= */ false);
         }
     }
 
@@ -6072,13 +6708,17 @@
         final FillContext context = getFillContextByRequestIdLocked(requestId);
 
         if (context == null) {
-            wtf(null, "createAuthFillInIntentLocked(): no FillContext. requestId=%d; mContexts=%s",
-                    requestId, mContexts);
+            wtf(
+                    null,
+                    "createAuthFillInIntentLocked(): no FillContext. requestId=%d; mContexts=%s",
+                    requestId,
+                    mContexts);
             return null;
         }
         if (mLastInlineSuggestionsRequest != null
                 && mLastInlineSuggestionsRequest.first == requestId) {
-            fillInIntent.putExtra(AutofillManager.EXTRA_INLINE_SUGGESTIONS_REQUEST,
+            fillInIntent.putExtra(
+                    AutofillManager.EXTRA_INLINE_SUGGESTIONS_REQUEST,
                     mLastInlineSuggestionsRequest.second);
         }
         fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
@@ -6121,12 +6761,15 @@
         }
     }
 
-    private void startAuthentication(int authenticationId, IntentSender intent,
-            Intent fillInIntent, boolean authenticateInline) {
+    private void startAuthentication(
+            int authenticationId,
+            IntentSender intent,
+            Intent fillInIntent,
+            boolean authenticateInline) {
         try {
             synchronized (mLock) {
-                mClient.authenticate(id, authenticationId, intent, fillInIntent,
-                        authenticateInline);
+                mClient.authenticate(
+                        id, authenticationId, intent, fillInIntent, authenticateInline);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "Error launching auth intent", e);
@@ -6139,22 +6782,18 @@
      * @hide
      */
     static final class SaveResult {
-        /**
-         * Whether to record the save dialog has been shown.
-         */
+        /** Whether to record the save dialog has been shown. */
         private boolean mLogSaveShown;
 
-        /**
-         * Whether to remove the session.
-         */
+        /** Whether to remove the session. */
         private boolean mRemoveSession;
 
-        /**
-         * The reason why a save dialog was not shown.
-         */
+        /** The reason why a save dialog was not shown. */
         @NoSaveReason private int mSaveDialogNotShowReason;
 
-        SaveResult(boolean logSaveShown, boolean removeSession,
+        SaveResult(
+                boolean logSaveShown,
+                boolean removeSession,
                 @NoSaveReason int saveDialogNotShowReason) {
             mLogSaveShown = logSaveShown;
             mRemoveSession = removeSession;
@@ -6218,15 +6857,19 @@
 
         @Override
         public String toString() {
-            return "SaveResult: [logSaveShown=" + mLogSaveShown
-                    + ", removeSession=" + mRemoveSession
-                    + ", saveDialogNotShowReason=" + mSaveDialogNotShowReason + "]";
+            return "SaveResult: [logSaveShown="
+                    + mLogSaveShown
+                    + ", removeSession="
+                    + mRemoveSession
+                    + ", saveDialogNotShowReason="
+                    + mSaveDialogNotShowReason
+                    + "]";
         }
     }
 
     /**
-     * Class maintaining the state of the requests to
-     * {@link android.service.assist.classification.FieldClassificationService}.
+     * Class maintaining the state of the requests to {@link
+     * android.service.assist.classification.FieldClassificationService}.
      */
     private static final class ClassificationState {
 
@@ -6234,18 +6877,16 @@
          * Initial state indicating that the request for classification hasn't been triggered yet.
          */
         private static final int STATE_INITIAL = 1;
-        /**
-         * Assist request has been triggered, but awaiting response.
-         */
+
+        /** Assist request has been triggered, but awaiting response. */
         private static final int STATE_PENDING_ASSIST_REQUEST = 2;
-        /**
-         * Classification request has been triggered, but awaiting response.
-         */
+
+        /** Classification request has been triggered, but awaiting response. */
         private static final int STATE_PENDING_REQUEST = 3;
-        /**
-         * Classification response has been received.
-         */
+
+        /** Classification response has been received. */
         private static final int STATE_RESPONSE = 4;
+
         /**
          * Classification state has been invalidated, and the last response may no longer be valid.
          * This could occur due to various reasons like views changing their layouts, becoming
@@ -6254,15 +6895,17 @@
          */
         private static final int STATE_INVALIDATED = 5;
 
-        @IntDef(prefix = { "STATE_" }, value = {
-                STATE_INITIAL,
-                STATE_PENDING_ASSIST_REQUEST,
-                STATE_PENDING_REQUEST,
-                STATE_RESPONSE,
-                STATE_INVALIDATED
-        })
+        @IntDef(
+                prefix = {"STATE_"},
+                value = {
+                    STATE_INITIAL,
+                    STATE_PENDING_ASSIST_REQUEST,
+                    STATE_PENDING_REQUEST,
+                    STATE_RESPONSE,
+                    STATE_INVALIDATED
+                })
         @Retention(RetentionPolicy.SOURCE)
-        @interface ClassificationRequestState{}
+        @interface ClassificationRequestState {}
 
         @GuardedBy("mLock")
         private @ClassificationRequestState int mState = STATE_INITIAL;
@@ -6284,8 +6927,8 @@
 
         /**
          * Typically, there would be a 1:1 mapping. However, in certain cases, we may have a hint
-         * being applicable to many types. An example of this being new/change password forms,
-         * where you need to confirm the passward twice.
+         * being applicable to many types. An example of this being new/change password forms, where
+         * you need to confirm the passward twice.
          */
         @GuardedBy("mLock")
         private ArrayMap<String, Set<AutofillId>> mHintsToAutofillIdMap;
@@ -6317,8 +6960,9 @@
 
         /**
          * Process the response received.
+         *
          * @return true if the response was processed, false otherwise. If there wasn't any
-         * response, yet this function was called, it would return false.
+         *     response, yet this function was called, it would return false.
          */
         @GuardedBy("mLock")
         private boolean processResponse() {
@@ -6358,7 +7002,9 @@
         }
 
         @GuardedBy("mLock")
-        private static void processDetections(Set<String> detections, AutofillId id,
+        private static void processDetections(
+                Set<String> detections,
+                AutofillId id,
                 ArrayMap<String, Set<AutofillId>> currentMap) {
             for (String detection : detections) {
                 Set<AutofillId> autofillIds;
@@ -6416,37 +7062,67 @@
         @Override
         public String toString() {
             return "ClassificationState: ["
-                    + "state=" + stateToString()
-                    + ", mPendingFieldClassificationRequest=" + mPendingFieldClassificationRequest
-                    + ", mLastFieldClassificationResponse=" + mLastFieldClassificationResponse
-                    + ", mClassificationHintsMap=" + mClassificationHintsMap
-                    + ", mClassificationGroupHintsMap=" + mClassificationGroupHintsMap
-                    + ", mHintsToAutofillIdMap=" + mHintsToAutofillIdMap
-                    + ", mGroupHintsToAutofillIdMap=" + mGroupHintsToAutofillIdMap
+                    + "state="
+                    + stateToString()
+                    + ", mPendingFieldClassificationRequest="
+                    + mPendingFieldClassificationRequest
+                    + ", mLastFieldClassificationResponse="
+                    + mLastFieldClassificationResponse
+                    + ", mClassificationHintsMap="
+                    + mClassificationHintsMap
+                    + ", mClassificationGroupHintsMap="
+                    + mClassificationGroupHintsMap
+                    + ", mHintsToAutofillIdMap="
+                    + mHintsToAutofillIdMap
+                    + ", mGroupHintsToAutofillIdMap="
+                    + mGroupHintsToAutofillIdMap
                     + "]";
         }
-
     }
 
     @Override
     public String toString() {
-        return "Session: [id=" + id + ", component=" + mComponentName
-                + ", state=" + sessionStateAsString(mSessionState) + "]";
+        return "Session: [id="
+                + id
+                + ", component="
+                + mComponentName
+                + ", state="
+                + sessionStateAsString(mSessionState)
+                + "]";
     }
 
     @GuardedBy("mLock")
     void dumpLocked(String prefix, PrintWriter pw) {
         final String prefix2 = prefix + "  ";
-        pw.print(prefix); pw.print("id: "); pw.println(id);
-        pw.print(prefix); pw.print("uid: "); pw.println(uid);
-        pw.print(prefix); pw.print("taskId: "); pw.println(taskId);
-        pw.print(prefix); pw.print("flags: "); pw.println(mFlags);
-        pw.print(prefix); pw.print("displayId: "); pw.println(mContext.getDisplayId());
-        pw.print(prefix); pw.print("state: "); pw.println(sessionStateAsString(mSessionState));
-        pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
-        pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
-        pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
-        pw.print(prefix); pw.print("Time to show UI: ");
+        pw.print(prefix);
+        pw.print("id: ");
+        pw.println(id);
+        pw.print(prefix);
+        pw.print("uid: ");
+        pw.println(uid);
+        pw.print(prefix);
+        pw.print("taskId: ");
+        pw.println(taskId);
+        pw.print(prefix);
+        pw.print("flags: ");
+        pw.println(mFlags);
+        pw.print(prefix);
+        pw.print("displayId: ");
+        pw.println(mContext.getDisplayId());
+        pw.print(prefix);
+        pw.print("state: ");
+        pw.println(sessionStateAsString(mSessionState));
+        pw.print(prefix);
+        pw.print("mComponentName: ");
+        pw.println(mComponentName);
+        pw.print(prefix);
+        pw.print("mActivityToken: ");
+        pw.println(mActivityToken);
+        pw.print(prefix);
+        pw.print("mStartTime: ");
+        pw.println(mStartTime);
+        pw.print(prefix);
+        pw.print("Time to show UI: ");
         if (mUiShownTime == 0) {
             pw.println("N/A");
         } else {
@@ -6454,41 +7130,67 @@
             pw.println();
         }
         final int requestLogsSizes = mRequestLogs.size();
-        pw.print(prefix); pw.print("mSessionLogs: "); pw.println(requestLogsSizes);
+        pw.print(prefix);
+        pw.print("mSessionLogs: ");
+        pw.println(requestLogsSizes);
         for (int i = 0; i < requestLogsSizes; i++) {
             final int requestId = mRequestLogs.keyAt(i);
             final LogMaker log = mRequestLogs.valueAt(i);
-            pw.print(prefix2); pw.print('#'); pw.print(i); pw.print(": req=");
-            pw.print(requestId); pw.print(", log=" ); dumpRequestLog(pw, log); pw.println();
+            pw.print(prefix2);
+            pw.print('#');
+            pw.print(i);
+            pw.print(": req=");
+            pw.print(requestId);
+            pw.print(", log=");
+            dumpRequestLog(pw, log);
+            pw.println();
         }
-        pw.print(prefix); pw.print("mResponses: ");
+        pw.print(prefix);
+        pw.print("mResponses: ");
         if (mResponses == null) {
             pw.println("null");
         } else {
             pw.println(mResponses.size());
             for (int i = 0; i < mResponses.size(); i++) {
-                pw.print(prefix2); pw.print('#'); pw.print(i);
-                pw.print(' '); pw.println(mResponses.valueAt(i));
+                pw.print(prefix2);
+                pw.print('#');
+                pw.print(i);
+                pw.print(' ');
+                pw.println(mResponses.valueAt(i));
             }
         }
-        pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
-        pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
-        pw.print(prefix); pw.print("mShowingSaveUi: "); pw.println(mSessionFlags.mShowingSaveUi);
-        pw.print(prefix); pw.print("mPendingSaveUi: "); pw.println(mPendingSaveUi);
+        pw.print(prefix);
+        pw.print("mCurrentViewId: ");
+        pw.println(mCurrentViewId);
+        pw.print(prefix);
+        pw.print("mDestroyed: ");
+        pw.println(mDestroyed);
+        pw.print(prefix);
+        pw.print("mShowingSaveUi: ");
+        pw.println(mSessionFlags.mShowingSaveUi);
+        pw.print(prefix);
+        pw.print("mPendingSaveUi: ");
+        pw.println(mPendingSaveUi);
         final int numberViews = mViewStates.size();
-        pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
+        pw.print(prefix);
+        pw.print("mViewStates size: ");
+        pw.println(mViewStates.size());
         for (int i = 0; i < numberViews; i++) {
-            pw.print(prefix); pw.print("ViewState at #"); pw.println(i);
+            pw.print(prefix);
+            pw.print("ViewState at #");
+            pw.println(i);
             mViewStates.valueAt(i).dump(prefix2, pw);
         }
 
-        pw.print(prefix); pw.print("mContexts: " );
+        pw.print(prefix);
+        pw.print("mContexts: ");
         if (mContexts != null) {
             int numContexts = mContexts.size();
             for (int i = 0; i < numContexts; i++) {
                 FillContext context = mContexts.get(i);
 
-                pw.print(prefix2); pw.print(context);
+                pw.print(prefix2);
+                pw.print(context);
                 if (sVerbose) {
                     pw.println("AssistStructure dumped at logcat)");
 
@@ -6500,43 +7202,62 @@
             pw.println("null");
         }
 
-        pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
+        pw.print(prefix);
+        pw.print("mHasCallback: ");
+        pw.println(mHasCallback);
         if (mClientState != null) {
-            pw.print(prefix); pw.print("mClientState: "); pw.print(mClientState.getSize()); pw
-                .println(" bytes");
+            pw.print(prefix);
+            pw.print("mClientState: ");
+            pw.print(mClientState.getSize());
+            pw.println(" bytes");
         }
-        pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
-        pw.print(prefix); pw.print("mUrlBar: ");
+        pw.print(prefix);
+        pw.print("mCompatMode: ");
+        pw.println(mCompatMode);
+        pw.print(prefix);
+        pw.print("mUrlBar: ");
         if (mUrlBar == null) {
             pw.println("N/A");
         } else {
-            pw.print("id="); pw.print(mUrlBar.getAutofillId());
-            pw.print(" domain="); pw.print(mUrlBar.getWebDomain());
-            pw.print(" text="); Helper.printlnRedactedText(pw, mUrlBar.getText());
+            pw.print("id=");
+            pw.print(mUrlBar.getAutofillId());
+            pw.print(" domain=");
+            pw.print(mUrlBar.getWebDomain());
+            pw.print(" text=");
+            Helper.printlnRedactedText(pw, mUrlBar.getText());
         }
-        pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
-                mSaveOnAllViewsInvisible);
-        pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
+        pw.print(prefix);
+        pw.print("mSaveOnAllViewsInvisible: ");
+        pw.println(mSaveOnAllViewsInvisible);
+        pw.print(prefix);
+        pw.print("mSelectedDatasetIds: ");
+        pw.println(mSelectedDatasetIds);
         if (mSessionFlags.mAugmentedAutofillOnly) {
-            pw.print(prefix); pw.println("For Augmented Autofill Only");
+            pw.print(prefix);
+            pw.println("For Augmented Autofill Only");
         }
         if (mSessionFlags.mFillDialogDisabled) {
-            pw.print(prefix); pw.println("Fill Dialog disabled");
+            pw.print(prefix);
+            pw.println("Fill Dialog disabled");
         }
         if (mLastFillDialogTriggerIds != null) {
-            pw.print(prefix); pw.println("Last Fill Dialog trigger ids: ");
+            pw.print(prefix);
+            pw.println("Last Fill Dialog trigger ids: ");
             pw.println(mSelectedDatasetIds);
         }
         if (mAugmentedAutofillDestroyer != null) {
-            pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer");
+            pw.print(prefix);
+            pw.println("has mAugmentedAutofillDestroyer");
         }
         if (mAugmentedRequestsLogs != null) {
-            pw.print(prefix); pw.print("number augmented requests: ");
+            pw.print(prefix);
+            pw.print("number augmented requests: ");
             pw.println(mAugmentedRequestsLogs.size());
         }
 
         if (mAugmentedAutofillableIds != null) {
-            pw.print(prefix); pw.print("mAugmentedAutofillableIds: ");
+            pw.print(prefix);
+            pw.print("mAugmentedAutofillableIds: ");
             pw.println(mAugmentedAutofillableIds);
         }
         if (mRemoteFillService != null) {
@@ -6545,21 +7266,32 @@
     }
 
     private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
-        pw.print("CAT="); pw.print(log.getCategory());
+        pw.print("CAT=");
+        pw.print(log.getCategory());
         pw.print(", TYPE=");
         final int type = log.getType();
         switch (type) {
-            case MetricsEvent.TYPE_SUCCESS: pw.print("SUCCESS"); break;
-            case MetricsEvent.TYPE_FAILURE: pw.print("FAILURE"); break;
-            case MetricsEvent.TYPE_CLOSE: pw.print("CLOSE"); break;
-            default: pw.print("UNSUPPORTED");
+            case MetricsEvent.TYPE_SUCCESS:
+                pw.print("SUCCESS");
+                break;
+            case MetricsEvent.TYPE_FAILURE:
+                pw.print("FAILURE");
+                break;
+            case MetricsEvent.TYPE_CLOSE:
+                pw.print("CLOSE");
+                break;
+            default:
+                pw.print("UNSUPPORTED");
         }
-        pw.print('('); pw.print(type); pw.print(')');
-        pw.print(", PKG="); pw.print(log.getPackageName());
-        pw.print(", SERVICE="); pw.print(log
-                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
-        pw.print(", ORDINAL="); pw.print(log
-                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
+        pw.print('(');
+        pw.print(type);
+        pw.print(')');
+        pw.print(", PKG=");
+        pw.print(log.getPackageName());
+        pw.print(", SERVICE=");
+        pw.print(log.getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
+        pw.print(", ORDINAL=");
+        pw.print(log.getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
         dumpNumericValue(pw, log, "FLAGS", MetricsEvent.FIELD_AUTOFILL_FLAGS);
         dumpNumericValue(pw, log, "NUM_DATASETS", MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS);
         dumpNumericValue(pw, log, "UI_LATENCY", MetricsEvent.FIELD_AUTOFILL_DURATION);
@@ -6569,64 +7301,86 @@
             pw.print(", AUTH_STATUS=");
             switch (authStatus) {
                 case MetricsEvent.AUTOFILL_AUTHENTICATED:
-                    pw.print("AUTHENTICATED"); break;
+                    pw.print("AUTHENTICATED");
+                    break;
                 case MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED:
-                    pw.print("DATASET_AUTHENTICATED"); break;
+                    pw.print("DATASET_AUTHENTICATED");
+                    break;
                 case MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION:
-                    pw.print("INVALID_AUTHENTICATION"); break;
+                    pw.print("INVALID_AUTHENTICATION");
+                    break;
                 case MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION:
-                    pw.print("INVALID_DATASET_AUTHENTICATION"); break;
-                default: pw.print("UNSUPPORTED");
+                    pw.print("INVALID_DATASET_AUTHENTICATION");
+                    break;
+                default:
+                    pw.print("UNSUPPORTED");
             }
-            pw.print('('); pw.print(authStatus); pw.print(')');
+            pw.print('(');
+            pw.print(authStatus);
+            pw.print(')');
         }
-        dumpNumericValue(pw, log, "FC_IDS",
-                MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
-        dumpNumericValue(pw, log, "COMPAT_MODE",
-                MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
+        dumpNumericValue(
+                pw, log, "FC_IDS", MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
+        dumpNumericValue(pw, log, "COMPAT_MODE", MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
     }
 
-    private static void dumpNumericValue(@NonNull PrintWriter pw, @NonNull LogMaker log,
-            @NonNull String field, int tag) {
+    private static void dumpNumericValue(
+            @NonNull PrintWriter pw, @NonNull LogMaker log, @NonNull String field, int tag) {
         final int value = getNumericValue(log, tag);
         if (value != 0) {
-            pw.print(", "); pw.print(field); pw.print('='); pw.print(value);
+            pw.print(", ");
+            pw.print(field);
+            pw.print('=');
+            pw.print(value);
         }
     }
 
-    void sendCredentialManagerResponseToApp(@Nullable GetCredentialResponse response,
-            @Nullable GetCredentialException exception, @NonNull AutofillId viewId) {
+    void sendCredentialManagerResponseToApp(
+            @Nullable GetCredentialResponse response,
+            @Nullable GetCredentialException exception,
+            @NonNull AutofillId viewId) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#sendCredentialManagerResponseToApp() rejected "
-                        + "- session: " + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#sendCredentialManagerResponseToApp() rejected "
+                                + "- session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             try {
                 final ViewState viewState = mViewStates.get(viewId);
                 if (mService.getMaster().getIsFillFieldsFromCurrentSessionOnly()
-                        && viewState != null && viewState.id.getSessionId() != id) {
+                        && viewState != null
+                        && viewState.id.getSessionId() != id) {
                     if (sVerbose) {
-                        Slog.v(TAG, "Skipping sending credential response to view: "
-                                + viewId + " as it isn't part of the current session: " + id);
+                        Slog.v(
+                                TAG,
+                                "Skipping sending credential response to view: "
+                                        + viewId
+                                        + " as it isn't part of the current session: "
+                                        + id);
                     }
                 }
                 if (exception != null) {
                     if (viewId.isVirtualInt()) {
-                        sendResponseToViewNode(viewId, /*response=*/ null, exception);
+                        sendResponseToViewNode(viewId, /* response= */ null, exception);
                     } else {
-                        mClient.onGetCredentialException(id, viewId, exception.getType(),
-                                exception.getMessage());
+                        mClient.onGetCredentialException(
+                                id, viewId, exception.getType(), exception.getMessage());
                     }
                 } else if (response != null) {
                     if (viewId.isVirtualInt()) {
-                        sendResponseToViewNode(viewId, response, /*exception=*/ null);
+                        sendResponseToViewNode(viewId, response, /* exception= */ null);
                     } else {
                         mClient.onGetCredentialResponse(id, viewId, response);
                     }
                 } else {
-                    Slog.w(TAG, "sendCredentialManagerResponseToApp called with null response"
-                            + "and exception");
+                    Slog.w(
+                            TAG,
+                            "sendCredentialManagerResponseToApp called with null response"
+                                    + "and exception");
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error sending credential response to activity: " + e);
@@ -6635,23 +7389,20 @@
     }
 
     @GuardedBy("mLock")
-    private void sendResponseToViewNode(AutofillId viewId, GetCredentialResponse response,
-            GetCredentialException exception) {
+    private void sendResponseToViewNode(
+            AutofillId viewId, GetCredentialResponse response, GetCredentialException exception) {
         ViewNode viewNode = getViewNodeFromContextsLocked(viewId);
         if (viewNode != null && viewNode.getPendingCredentialCallback() != null) {
             Bundle resultData = new Bundle();
             if (response != null) {
                 resultData.putParcelable(
-                        CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
-                        response);
-                viewNode.getPendingCredentialCallback().send(SUCCESS_CREDMAN_SELECTOR,
-                        resultData);
+                        CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE, response);
+                viewNode.getPendingCredentialCallback().send(SUCCESS_CREDMAN_SELECTOR, resultData);
             } else if (exception != null) {
                 resultData.putStringArray(
                         CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
                         new String[] {exception.getType(), exception.getMessage()});
-                viewNode.getPendingCredentialCallback().send(FAILURE_CREDMAN_SELECTOR,
-                        resultData);
+                viewNode.getPendingCredentialCallback().send(FAILURE_CREDMAN_SELECTOR, resultData);
             }
         } else {
             Slog.w(TAG, "View node not found after GetCredentialResponse");
@@ -6661,8 +7412,9 @@
     void autoFillApp(Dataset dataset) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#autoFillApp() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#autoFillApp() rejected - session: " + id + " destroyed");
                 return;
             }
             try {
@@ -6671,8 +7423,11 @@
                 final List<AutofillId> ids = new ArrayList<>(entryCount);
                 final List<AutofillValue> values = new ArrayList<>(entryCount);
                 boolean waitingDatasetAuth = false;
-                boolean hideHighlight = (entryCount == 1
-                        && dataset.getFieldIds().get(0).equals(mCurrentViewId));
+                boolean hideHighlight =
+                        highlightAutofillSingleField()
+                                ? false
+                                : (entryCount == 1
+                                        && dataset.getFieldIds().get(0).equals(mCurrentViewId));
                 // Count how many views are filtered because they are not in current session
                 int numOfViewsFiltered = 0;
                 for (int i = 0; i < entryCount; i++) {
@@ -6682,10 +7437,15 @@
                     final AutofillId viewId = dataset.getFieldIds().get(i);
                     final ViewState viewState = mViewStates.get(viewId);
                     if (mService.getMaster().getIsFillFieldsFromCurrentSessionOnly()
-                            && viewState != null && viewState.id.getSessionId() != id) {
+                            && viewState != null
+                            && viewState.id.getSessionId() != id) {
                         if (sVerbose) {
-                            Slog.v(TAG, "Skipping filling view: " +
-                                    viewId + " as it isn't part of the current session: " + id);
+                            Slog.v(
+                                    TAG,
+                                    "Skipping filling view: "
+                                            + viewId
+                                            + " as it isn't part of the current session: "
+                                            + id);
                         }
                         numOfViewsFiltered += 1;
                         continue;
@@ -6721,8 +7481,12 @@
                     }
                     // does not matter the value of isPrimary because null response won't be
                     // overridden.
-                    setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED,
-                            /* clearResponse= */ false, /* isPrimary= */ true);
+                    setViewStatesLocked(
+                            null,
+                            dataset,
+                            ViewState.STATE_AUTOFILLED,
+                            /* clearResponse= */ false,
+                            /* isPrimary= */ true);
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error autofilling activity: " + e);
@@ -6750,7 +7514,7 @@
         mSessionCommittedEventLogger.maybeSetCommitReason(val);
         mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
         mSessionCommittedEventLogger.maybeSetSessionDurationMillis(
-            SystemClock.elapsedRealtime() - mStartTime);
+                SystemClock.elapsedRealtime() - mStartTime);
         mFillRequestEventLogger.logAndEndEvent();
         mFillResponseEventLogger.logAndEndEvent();
         mPresentationStatsEventLogger.logAndEndEvent("log all events");
@@ -6808,8 +7572,8 @@
             }
         }
 
-        final int totalAugmentedRequests = mAugmentedRequestsLogs == null ? 0
-                : mAugmentedRequestsLogs.size();
+        final int totalAugmentedRequests =
+                mAugmentedRequestsLogs == null ? 0 : mAugmentedRequestsLogs.size();
         if (totalAugmentedRequests > 0) {
             if (sVerbose) {
                 Slog.v(TAG, "destroyLocked(): logging " + totalRequests + " augmented requests");
@@ -6820,11 +7584,12 @@
             }
         }
 
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests);
+        final LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests);
         if (totalAugmentedRequests > 0) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS,
-                    totalAugmentedRequests);
+            log.addTaggedData(
+                    MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS, totalAugmentedRequests);
         }
         if (mSessionFlags.mAugmentedAutofillOnly) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_AUGMENTED_ONLY, 1);
@@ -6846,8 +7611,12 @@
     @GuardedBy("mLock")
     void forceRemoveFromServiceIfForAugmentedOnlyLocked() {
         if (sVerbose) {
-            Slog.v(TAG, "forceRemoveFromServiceIfForAugmentedOnlyLocked(" + this.id + "): "
-                    + mSessionFlags.mAugmentedAutofillOnly);
+            Slog.v(
+                    TAG,
+                    "forceRemoveFromServiceIfForAugmentedOnlyLocked("
+                            + this.id
+                            + "): "
+                            + mSessionFlags.mAugmentedAutofillOnly);
         }
         if (!mSessionFlags.mAugmentedAutofillOnly) return;
 
@@ -6880,9 +7649,7 @@
         }
     }
 
-    /**
-     * Thread-safe version of {@link #removeFromServiceLocked()}.
-     */
+    /** Thread-safe version of {@link #removeFromServiceLocked()}. */
     private void removeFromService() {
         synchronized (mLock) {
             removeFromServiceLocked();
@@ -6897,8 +7664,11 @@
     void removeFromServiceLocked() {
         if (sVerbose) Slog.v(TAG, "removeFromServiceLocked(" + this.id + "): " + mPendingSaveUi);
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#removeFromServiceLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#removeFromServiceLocked() rejected - session: "
+                            + id
+                            + " destroyed");
             return;
         }
         if (isSaveUiPendingLocked()) {
@@ -6922,18 +7692,16 @@
     }
 
     /**
-     * Checks whether this session is hiding the Save UI to handle a custom description link for
-     * a specific {@code token} created by
-     * {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}.
+     * Checks whether this session is hiding the Save UI to handle a custom description link for a
+     * specific {@code token} created by {@link PendingUi#PendingUi(IBinder, int,
+     * IAutoFillManagerClient)}.
      */
     @GuardedBy("mLock")
     boolean isSaveUiPendingForTokenLocked(@NonNull IBinder token) {
         return isSaveUiPendingLocked() && token.equals(mPendingSaveUi.getToken());
     }
 
-    /**
-     * Checks whether this session is hiding the Save UI to handle a custom description link.
-     */
+    /** Checks whether this session is hiding the Save UI to handle a custom description link. */
     @GuardedBy("mLock")
     private boolean isSaveUiPendingLocked() {
         return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING;
@@ -6942,8 +7710,8 @@
     // Return latest response index in mResponses SparseArray.
     @GuardedBy("mLock")
     private int getLastResponseIndexLocked() {
-        if (mResponses == null  || mResponses.size() == 0) {
-          return -1;
+        if (mResponses == null || mResponses.size() == 0) {
+            return -1;
         }
         List<Integer> requestIdList = new ArrayList<>();
         final int responseCount = mResponses.size();
@@ -6967,15 +7735,16 @@
 
     @GuardedBy("mLock")
     private void logAuthenticationStatusLocked(int requestId, int status) {
-        addTaggedDataToRequestLogLocked(requestId,
-                MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
+        addTaggedDataToRequestLogLocked(
+                requestId, MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
     }
 
     @GuardedBy("mLock")
     private void addTaggedDataToRequestLogLocked(int requestId, int tag, @Nullable Object value) {
         final LogMaker requestLog = mRequestLogs.get(requestId);
         if (requestLog == null) {
-            Slog.w(TAG,
+            Slog.w(
+                    TAG,
                     "addTaggedDataToRequestLogLocked(tag=" + tag + "): no log for id " + requestId);
             return;
         }
@@ -6983,20 +7752,33 @@
     }
 
     @GuardedBy("mLock")
-    private void logAugmentedAutofillRequestLocked(int mode,
-            ComponentName augmentedRemoteServiceName, AutofillId focusedId, boolean isWhitelisted,
+    private void logAugmentedAutofillRequestLocked(
+            int mode,
+            ComponentName augmentedRemoteServiceName,
+            AutofillId focusedId,
+            boolean isWhitelisted,
             Boolean isInline) {
         final String historyItem =
-                "aug:id=" + id + " u=" + uid + " m=" + mode
-                        + " a=" + ComponentName.flattenToShortString(mComponentName)
-                        + " f=" + focusedId
-                        + " s=" + augmentedRemoteServiceName
-                        + " w=" + isWhitelisted
-                        + " i=" + isInline;
+                "aug:id="
+                        + id
+                        + " u="
+                        + uid
+                        + " m="
+                        + mode
+                        + " a="
+                        + ComponentName.flattenToShortString(mComponentName)
+                        + " f="
+                        + focusedId
+                        + " s="
+                        + augmentedRemoteServiceName
+                        + " w="
+                        + isWhitelisted
+                        + " i="
+                        + isInline;
         mService.getMaster().logRequestLocked(historyItem);
     }
 
-    private void wtf(@Nullable Exception e, String fmt, Object...args) {
+    private void wtf(@Nullable Exception e, String fmt, Object... args) {
         final String message = String.format(fmt, args);
         synchronized (mLock) {
             mWtfHistory.log(message);
@@ -7051,13 +7833,9 @@
         mClassificationState.updateResponseReceived(response);
     }
 
-    public void onClassificationRequestFailure(int requestId, @Nullable CharSequence message) {
+    public void onClassificationRequestFailure(int requestId, @Nullable CharSequence message) {}
 
-    }
-
-    public void onClassificationRequestTimeout(int requestId) {
-
-    }
+    public void onClassificationRequestTimeout(int requestId) {}
 
     @Override
     public void onServiceDied(@NonNull RemoteFieldClassificationService service) {
@@ -7070,12 +7848,12 @@
 
     @Override
     public void logFieldClassificationEvent(
-            long startTime, FieldClassificationResponse response,
+            long startTime,
+            FieldClassificationResponse response,
             @FieldClassificationEventLogger.FieldClassificationStatus int status) {
         final FieldClassificationEventLogger logger = FieldClassificationEventLogger.createLogger();
         logger.startNewLogForRequest();
-        logger.maybeSetLatencyMillis(
-                SystemClock.elapsedRealtime() - startTime);
+        logger.maybeSetLatencyMillis(SystemClock.elapsedRealtime() - startTime);
         logger.maybeSetAppPackageUid(uid);
         logger.maybeSetNextFillRequestId(mFillRequestIdSnapshot + 1);
         logger.maybeSetRequestId(sIdCounterForPcc.get());
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 57c643b..a7aab49 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -160,11 +160,13 @@
             HardwareBuffer snapshotBuffer = null;
             int colorSpaceId = 0;
 
+            TaskSnapshot snapshot = null;
             // Skip taking TaskSnapshot when bitmap is provided.
             if (!imageContextRequestExtras.containsKey(ContentSuggestionsManager.EXTRA_BITMAP)) {
                 // Can block, so call before acquiring the lock.
-                TaskSnapshot snapshot =
-                        mActivityTaskManagerInternal.getTaskSnapshotBlocking(taskId, false);
+                snapshot = mActivityTaskManagerInternal.getTaskSnapshotBlocking(
+                        taskId, false /* isLowResolution */,
+                        TaskSnapshot.REFERENCE_CONTENT_SUGGESTION);
                 if (snapshot != null) {
                     snapshotBuffer = snapshot.getHardwareBuffer();
                     ColorSpace colorSpace = snapshot.getColorSpace();
@@ -185,6 +187,9 @@
                     }
                 }
             }
+            if (snapshot != null) {
+                snapshot.removeReference(TaskSnapshot.REFERENCE_CONTENT_SUGGESTION);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 05d07ae..485bf31 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -1523,7 +1523,7 @@
                 @Override
                 public void onApexStaged(ApexStagedEvent event) throws RemoteException {
                     Slog.d(TAG, "A new APEX has been staged for update. There are currently "
-                            + event.stagedApexModuleNames.length + " APEX(s) staged for update. "
+                            + event.stagedApexInfos.length + " APEX(s) staged for update. "
                             + "Scheduling measurement...");
                     UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
                             BinaryTransparencyService.this);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index f8857d3..d13dd2f 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -443,6 +443,11 @@
         mDreamsDisabledByAmbientModeSuppression = disabledByAmbientModeSuppression;
     }
 
+    @VisibleForTesting
+    void setCurrentUser(int currentUserId) {
+        mCurrentUser = currentUserId;
+    }
+
     @Override
     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         mCurrentUser = to.getUserIdentifier();
@@ -864,9 +869,9 @@
                     throw new IllegalArgumentException("Unknown mode: " + mode);
             }
 
-            final int user = UserHandle.getCallingUserId();
-            enforceCurrentUserIfVisibleBackgroundEnabled(user);
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
 
+            final int user = UserHandle.getCallingUserId();
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -929,7 +934,7 @@
                 @AttentionModeThemeOverlayType int attentionModeThemeOverlayType) {
             setAttentionModeThemeOverlay_enforcePermission();
 
-            enforceCurrentUserIfVisibleBackgroundEnabled(UserHandle.getCallingUserId());
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
 
             synchronized (mLock) {
                 if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) {
@@ -1020,16 +1025,16 @@
                 return false;
             }
             final int user = Binder.getCallingUserHandle().getIdentifier();
-            enforceCurrentUserIfVisibleBackgroundEnabled(user);
-
             if (user != mCurrentUser && getContext().checkCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS)
                     != PackageManager.PERMISSION_GRANTED) {
                 Slog.e(TAG, "Target user is not current user,"
                         + " INTERACT_ACROSS_USERS permission is required");
                 return false;
-
             }
+
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+
             // Store the last requested bedtime night mode state so that we don't need to notify
             // anyone if the user decides to switch to the night mode to bedtime.
             if (modeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
@@ -1078,9 +1083,10 @@
                 Slog.e(TAG, "Set custom time start, requires MODIFY_DAY_NIGHT_MODE permission");
                 return;
             }
-            final int user = UserHandle.getCallingUserId();
-            enforceCurrentUserIfVisibleBackgroundEnabled(user);
 
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+
+            final int user = UserHandle.getCallingUserId();
             final long ident = Binder.clearCallingIdentity();
             try {
                 LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000);
@@ -1108,9 +1114,10 @@
                 Slog.e(TAG, "Set custom time end, requires MODIFY_DAY_NIGHT_MODE permission");
                 return;
             }
-            final int user = UserHandle.getCallingUserId();
-            enforceCurrentUserIfVisibleBackgroundEnabled(user);
 
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+
+            final int user = UserHandle.getCallingUserId();
             final long ident = Binder.clearCallingIdentity();
             try {
                 LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000);
@@ -1131,7 +1138,7 @@
             assertLegit(callingPackage);
             assertSingleProjectionType(projectionType);
             enforceProjectionTypePermissions(projectionType);
-            enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
 
             synchronized (mLock) {
                 if (mProjectionHolders == null) {
@@ -1177,7 +1184,7 @@
             assertLegit(callingPackage);
             assertSingleProjectionType(projectionType);
             enforceProjectionTypePermissions(projectionType);
-            enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
 
             return releaseProjectionUnchecked(projectionType, callingPackage);
         }
@@ -1219,7 +1226,7 @@
                 return;
             }
 
-            enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
+            enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
 
             synchronized (mLock) {
                 if (mProjectionListeners == null) {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 12e8c57..947f6b7 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -48,7 +48,6 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.vcn.Flags;
 import android.net.vcn.IVcnManagementService;
 import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -447,22 +446,16 @@
         }
 
         final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+        final UserManager userManager = mContext.getSystemService(UserManager.class);
 
-        if (Flags.enforceMainUser()) {
-            final UserManager userManager = mContext.getSystemService(UserManager.class);
-
-            Binder.withCleanCallingIdentity(
-                    () -> {
-                        if (!Objects.equals(userManager.getMainUser(), userHandle)) {
-                            throw new SecurityException(
-                                    "VcnManagementService can only be used by callers running as"
-                                            + " the main user");
-                        }
-                    });
-        } else if (!userHandle.isSystem()) {
-            throw new SecurityException(
-                    "VcnManagementService can only be used by callers running as the primary user");
-        }
+        Binder.withCleanCallingIdentity(
+                () -> {
+                    if (!Objects.equals(userManager.getMainUser(), userHandle)) {
+                        throw new SecurityException(
+                                "VcnManagementService can only be used by callers running as"
+                                        + " the main user");
+                    }
+                });
     }
 
     private void enforceCallingUserAndCarrierPrivilege(
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index f5a297b..65a2c18 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -246,7 +246,7 @@
 
     static final int DEFAULT_MAX_SERVICE_CONNECTIONS_PER_PROCESS = 3000;
 
-    private static final boolean DEFAULT_USE_TIERED_CACHED_ADJ = false;
+    private static final boolean DEFAULT_USE_TIERED_CACHED_ADJ = Flags.oomadjusterCachedAppTiers();
     private static final long DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME = 60 * 1000;
 
     /**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 5236b03..7831c39 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -813,10 +813,8 @@
     private final Object mProcessChangeLock = new Object();
 
     /**
-     * All of the applications we currently have running organized by name.
-     * The keys are strings of the application package name (as
-     * returned by the package manager), and the keys are ApplicationRecord
-     * objects.
+     * All of the processes that are running organized by name.
+     * The keys are process names and the values are the associated ProcessRecord objects.
      */
     @CompositeRWLock({"mService", "mProcLock"})
     private final MyProcessMap mProcessNames = new MyProcessMap();
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index adf0e64..d67fea0 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -225,3 +225,11 @@
     description: "Migrate OomAdjuster pulled device state to a push model"
     bug: "302575389"
 }
+
+flag {
+    name: "oomadjuster_cached_app_tiers"
+    namespace: "system_performance"
+    is_fixed_read_only: true
+    description: "Assign cached oom_score_adj in tiers."
+    bug: "369893532"
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 60dbf3f..dbdc614 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -30,6 +30,7 @@
 import android.bluetooth.BluetoothProfile;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
+import android.content.AttributionSource;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -306,14 +307,13 @@
      * @param on true to enable speakerphone
      * @param eventSource for logging purposes
      */
-    /*package*/ void setSpeakerphoneOn(
-            IBinder cb, int uid, boolean on, boolean isPrivileged, String eventSource) {
-
+    /*package*/ void setSpeakerphoneOn(IBinder cb, @NonNull AttributionSource attributionSource,
+            boolean on, boolean isPrivileged, String eventSource) {
         if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + uid);
+            Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + attributionSource.getUid());
         }
-        postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
-                cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
+        postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(cb, attributionSource,
+                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
                 on, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged));
     }
 
@@ -332,16 +332,18 @@
      * @param eventSource for logging purposes
      * @return false if there is no device and no communication client
      */
-    /*package*/ boolean setCommunicationDevice(IBinder cb, int uid, AudioDeviceInfo device,
-                                               boolean isPrivileged, String eventSource) {
-
+    /*package*/ boolean setCommunicationDevice(IBinder cb,
+            @NonNull AttributionSource attributionSource, AudioDeviceInfo device,
+            boolean isPrivileged, String eventSource) {
         if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "setCommunicationDevice, device: " + device + ", uid: " + uid);
+            Log.v(TAG, "setCommunicationDevice, device: " + device
+                    + ", uid: " + attributionSource.getUid());
         }
 
         if (device == null) {
             synchronized (mDeviceStateLock) {
-                CommunicationRouteClient client = getCommunicationRouteClientForUid(uid);
+                CommunicationRouteClient client =
+                        getCommunicationRouteClientForUid(attributionSource.getUid());
                 if (client == null) {
                     return false;
                 }
@@ -351,7 +353,8 @@
             mCommunicationDeviceUpdateCount++;
             AudioDeviceAttributes deviceAttr =
                     (device != null) ? new AudioDeviceAttributes(device) : null;
-            CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, uid, deviceAttr,
+            CommunicationDeviceInfo deviceInfo =
+                    new CommunicationDeviceInfo(cb, attributionSource, deviceAttr,
                     device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged);
             postSetCommunicationDeviceForClient(deviceInfo);
         }
@@ -369,7 +372,8 @@
             Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo);
         }
         if (!deviceInfo.mOn) {
-            CommunicationRouteClient client = getCommunicationRouteClientForUid(deviceInfo.mUid);
+            CommunicationRouteClient client =
+                    getCommunicationRouteClientForUid(deviceInfo.mAttributionSource.getUid());
             if (client == null || (deviceInfo.mDevice != null
                     && !deviceInfo.mDevice.equals(client.getDevice()))) {
                 return;
@@ -377,53 +381,60 @@
         }
 
         AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null;
-        setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mUid, device,
-                deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource);
+        setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mAttributionSource,
+                device, deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged,
+                deviceInfo.mEventSource);
     }
 
     /**
      * Indicates if a Bluetooth SCO activation request owner is controlling
      * the SCO audio state itself or not.
-     * @param uid the UID of the SOC request owner app
+     * @param attributionSource the AttributionSource of the SCO request owner app
      * @return true if we should control SCO audio state, false otherwise
      */
-    private boolean shouldStartScoForUid(int uid) {
+    private boolean shouldStartScoForAttributionSource(AttributionSource attributionSource) {
+        if (attributionSource == null) {
+            return true;
+        }
+        int uid = attributionSource.getUid();
         return !(UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)
                 || UserHandle.isSameApp(uid, Process.PHONE_UID)
-                || UserHandle.isSameApp(uid, Process.SYSTEM_UID));
+                || (UserHandle.isSameApp(uid, Process.SYSTEM_UID)
+                    && "com.android.server.telecom".equals(attributionSource.getPackageName())));
     }
 
     @GuardedBy("mDeviceStateLock")
     /*package*/ void setCommunicationRouteForClient(
-                            IBinder cb, int uid, AudioDeviceAttributes device,
-                            int scoAudioMode, boolean isPrivileged, String eventSource) {
-
+            IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device,
+            int scoAudioMode, boolean isPrivileged, String eventSource) {
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "setCommunicationRouteForClient: device: " + device
                     + ", eventSource: " + eventSource);
         }
         AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
-                                        "setCommunicationRouteForClient for uid: " + uid
+                                        "setCommunicationRouteForClient for uid: "
+                                        + attributionSource.getUid()
                                         + " device: " + device + " isPrivileged: " + isPrivileged
                                         + " from API: " + eventSource)).printLog(TAG));
 
-        final int previousBtScoRequesterUid = bluetoothScoRequestOwnerUid();
+        final AttributionSource previousBtScoRequesterAS =
+                bluetoothScoRequestOwnerAttributionSource();
         CommunicationRouteClient client;
 
         // Save previous client route in case of failure to start BT SCO audio
         AudioDeviceAttributes prevClientDevice = null;
         boolean prevPrivileged = false;
-        client = getCommunicationRouteClientForUid(uid);
+        client = getCommunicationRouteClientForUid(attributionSource.getUid());
         if (client != null) {
             prevClientDevice = client.getDevice();
             prevPrivileged = client.isPrivileged();
         }
 
         if (device != null) {
-            client = addCommunicationRouteClient(cb, uid, device, isPrivileged);
+            client = addCommunicationRouteClient(cb, attributionSource, device, isPrivileged);
             if (client == null) {
                 Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: "
-                        + uid + " and device: " + device);
+                        + attributionSource.getUid() + " and device: " + device);
             }
         } else {
             client = removeCommunicationRouteClient(cb, true);
@@ -431,22 +442,23 @@
         if (client == null) {
             return;
         }
-        final int btScoRequesterUid = bluetoothScoRequestOwnerUid();
-        final boolean isBtScoRequested = btScoRequesterUid != -1;
-        final boolean wasBtScoRequested = previousBtScoRequesterUid != -1;
+        final AttributionSource btScoRequesterAS = bluetoothScoRequestOwnerAttributionSource();
+        final boolean isBtScoRequested = btScoRequesterAS != null;
+        final boolean wasBtScoRequested = previousBtScoRequesterAS != null;
 
         if (mScoManagedByAudio) {
             if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive()
                     || !mBtHelper.isBluetoothScoRequestedInternally())) {
                 boolean scoStarted = false;
-                if (shouldStartScoForUid(btScoRequesterUid)) {
+                if (shouldStartScoForAttributionSource(btScoRequesterAS)) {
                     scoStarted = mBtHelper.startBluetoothSco(scoAudioMode, eventSource);
                     if (!scoStarted) {
                         Log.w(TAG, "setCommunicationRouteForClient: "
-                                + "failure to start BT SCO for uid: " + uid);
+                                + "failure to start BT SCO for uid: " + attributionSource.getUid());
                         // clean up or restore previous client selection
                         if (prevClientDevice != null) {
-                            addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged);
+                            addCommunicationRouteClient(cb, attributionSource,
+                                    prevClientDevice, prevPrivileged);
                         } else {
                             removeCommunicationRouteClient(cb, true);
                         }
@@ -459,7 +471,7 @@
                     setBluetoothScoOn(true, "setCommunicationRouteForClient");
                 }
             } else if (!isBtScoRequested && wasBtScoRequested) {
-                if (shouldStartScoForUid(previousBtScoRequesterUid)) {
+                if (shouldStartScoForAttributionSource(previousBtScoRequesterAS)) {
                     mBtHelper.stopBluetoothSco(eventSource);
                 }
                 setBluetoothScoOn(false, "setCommunicationRouteForClient");
@@ -469,10 +481,11 @@
                     || !mBtHelper.isBluetoothScoRequestedInternally())) {
                 if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
                     Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: "
-                            + uid);
+                            + attributionSource.getUid());
                     // clean up or restore previous client selection
                     if (prevClientDevice != null) {
-                        addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged);
+                        addCommunicationRouteClient(cb, attributionSource,
+                                prevClientDevice, prevPrivileged);
                     } else {
                         removeCommunicationRouteClient(cb, true);
                     }
@@ -583,7 +596,7 @@
                 // Cancelling the route for this client will remove it from the stack and update
                 // the communication route.
                 CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(
-                        crc.getBinder(), crc.getUid(), device, false,
+                        crc.getBinder(), crc.getAttributionSource(), device, false,
                         BtHelper.SCO_MODE_UNDEFINED, "onCheckCommunicationDeviceRemoval",
                         crc.isPrivileged());
                 postSetCommunicationDeviceForClient(deviceInfo);
@@ -619,12 +632,11 @@
     @GuardedBy("mDeviceStateLock")
     /*package*/ void updateCommunicationRouteClientState(
                             CommunicationRouteClient client, boolean wasActive) {
-        int btScoRequesterUid = bluetoothScoRequestOwnerUid();
         client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid()));
         client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid()));
         if (wasActive != client.isActive()) {
-            postUpdateCommunicationRouteClient(
-                    btScoRequesterUid, "updateCommunicationRouteClientState");
+            postUpdateCommunicationRouteClient(bluetoothScoRequestOwnerAttributionSource(),
+                    "updateCommunicationRouteClientState");
         }
     }
 
@@ -810,21 +822,26 @@
     }
 
     /**
-     * Helper method on top of isBluetoothScoRequested() returning the UID of the
-     * BT SCO route request owner of -1 if SCO is not requested.
-     * @return the UID of the BT SCO route request owner of -1 if SCO is not requested.
+     * Helper method on top of isBluetoothScoRequested() returning the Attribution Source of the
+     * BT SCO route request owner or null if SCO is not requested.
+     * @return the AttributionSource of the BT SCO route request owner of null.
      */
     @GuardedBy("mDeviceStateLock")
-    /*package*/ int bluetoothScoRequestOwnerUid() {
+    /*package*/ @Nullable AttributionSource bluetoothScoRequestOwnerAttributionSource() {
         if (!isBluetoothScoRequested()) {
-            return -1;
+            return null;
         }
         CommunicationRouteClient crc = topCommunicationRouteClient();
         if (crc == null) {
-            return -1;
+            return null;
         }
-        return crc.getUid();
+        return crc.getAttributionSource();
     }
+
+    private static int safeUidFromAttributionSource(AttributionSource attributionSource) {
+        return (attributionSource != null) ? attributionSource.getUid() : -1;
+    }
+
     /**
      * Helper method on top of isDeviceRequestedForCommunication() indicating if
      * Bluetooth LE Audio communication device is currently requested or not.
@@ -1222,14 +1239,15 @@
     @GuardedBy("mDeviceStateLock")
     /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
         synchronized (mBluetoothAudioStateLock) {
-            int btScoRequesterUId = bluetoothScoRequestOwnerUid();
+            AttributionSource btScoRequesterAS = bluetoothScoRequestOwnerAttributionSource();
             Log.i(TAG, "setBluetoothScoOn: " + on + ", mBluetoothScoOn: "
-                    + mBluetoothScoOn + ", btScoRequesterUId: " + btScoRequesterUId
+                    + mBluetoothScoOn + ", btScoRequesterUId: "
+                    + safeUidFromAttributionSource(btScoRequesterAS)
                     + ", from: " + eventSource);
             mBluetoothScoOn = on;
             updateAudioHalBluetoothState();
             if (!mScoManagedByAudio) {
-                postUpdateCommunicationRouteClient(btScoRequesterUId, eventSource);
+                postUpdateCommunicationRouteClient(btScoRequesterAS, eventSource);
             }
         }
     }
@@ -1332,25 +1350,26 @@
         sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
     }
 
-    /*package*/ void startBluetoothScoForClient(IBinder cb, int uid, int scoAudioMode,
-                                                boolean isPrivileged, @NonNull String eventSource) {
-
+    /*package*/ void startBluetoothScoForClient(IBinder cb,
+            @NonNull AttributionSource attributionSource, int scoAudioMode, boolean isPrivileged,
+            @NonNull String eventSource) {
         if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "startBluetoothScoForClient, uid: " + uid);
+            Log.v(TAG, "startBluetoothScoForClient, uid: " + attributionSource.getUid());
         }
-        postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
-                cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
+        postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(cb, attributionSource,
+                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
                 true, scoAudioMode, eventSource, isPrivileged));
     }
 
-    /*package*/ void stopBluetoothScoForClient(
-                        IBinder cb, int uid, boolean isPrivileged, @NonNull String eventSource) {
-
+    /*package*/ void stopBluetoothScoForClient(IBinder cb,
+            @NonNull AttributionSource attributionSource, boolean isPrivileged,
+            @NonNull String eventSource) {
         if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "stopBluetoothScoForClient, uid: " + uid);
+            Log.v(TAG, "stopBluetoothScoForClient, uid: " + attributionSource.getUid());
         }
         postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
-                cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
+                cb, attributionSource, new AudioDeviceAttributes(
+                                              AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
                 false, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged));
     }
 
@@ -1566,10 +1585,21 @@
         sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client);
     }
 
+    private static final class UpdateCommRouteClientInfo {
+        @NonNull public final AttributionSource attributionSource;
+        @NonNull public final String eventSource;
+
+        UpdateCommRouteClientInfo(@NonNull AttributionSource attributionSource,
+                @NonNull String eventSource) {
+            this.attributionSource = attributionSource;
+            this.eventSource = eventSource;
+        }
+    }
+
     /*package*/ void postUpdateCommunicationRouteClient(
-            int btScoRequesterUid, String eventSource) {
-        sendILMsgNoDelay(MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
-                btScoRequesterUid, eventSource);
+            AttributionSource attributionSource, String eventSource) {
+        sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
+            new UpdateCommRouteClientInfo(attributionSource, eventSource));
     }
 
     /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
@@ -1600,18 +1630,18 @@
 
     /*package*/ static final class CommunicationDeviceInfo {
         final @NonNull IBinder mCb; // Identifies the requesting client for death handler
-        final int mUid; // Requester UID
+        final @NonNull AttributionSource mAttributionSource; // Requester attribution source
         final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset.
         final boolean mOn; // true if setting, false if resetting
         final int mScoAudioMode; // only used for SCO: requested audio mode
         final boolean mIsPrivileged; // true if the client app has MODIFY_PHONE_STATE permission
         final @NonNull String mEventSource; // caller identifier for logging
 
-        CommunicationDeviceInfo(@NonNull IBinder cb, int uid,
+        CommunicationDeviceInfo(@NonNull IBinder cb, @NonNull AttributionSource attributionSource,
                 @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode,
                 @NonNull String eventSource, boolean isPrivileged) {
             mCb = cb;
-            mUid = uid;
+            mAttributionSource = attributionSource;
             mDevice = device;
             mOn = on;
             mScoAudioMode = scoAudioMode;
@@ -1633,19 +1663,19 @@
             }
 
             return mCb.equals(((CommunicationDeviceInfo) o).mCb)
-                    && mUid == ((CommunicationDeviceInfo) o).mUid;
+                    && mAttributionSource.equals(((CommunicationDeviceInfo) o).mAttributionSource);
         }
 
         @Override
         public int hashCode() {
             // only hashing on the fields used in equals()
-            return Objects.hash(mCb.hashCode(), mUid);
+            return Objects.hash(mCb.hashCode(), mAttributionSource);
         }
 
         @Override
         public String toString() {
             return "CommunicationDeviceInfo mCb=" + mCb.toString()
-                    + " mUid=" + mUid
+                    + " mAttributionSource=" + mAttributionSource.toString()
                     + " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]"
                     + " mOn=" + mOn
                     + " mScoAudioMode=" + mScoAudioMode
@@ -1929,7 +1959,8 @@
                                         || btInfo.mProfile == BluetoothProfile.HEARING_AID
                                         || (mScoManagedByAudio
                                             && btInfo.mProfile == BluetoothProfile.HEADSET)) {
-                                    onUpdateCommunicationRouteClient(bluetoothScoRequestOwnerUid(),
+                                    onUpdateCommunicationRouteClient(
+                                            bluetoothScoRequestOwnerAttributionSource(),
                                             "setBluetoothActiveDevice");
                                 }
                             }
@@ -1998,11 +2029,11 @@
                 case MSG_IL_SET_MODE_OWNER:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            int btScoRequesterUid = bluetoothScoRequestOwnerUid();
                             mAudioModeOwner = (AudioModeInfo) msg.obj;
                             if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
                                 onUpdateCommunicationRouteClient(
-                                        btScoRequesterUid, "setNewModeOwner");
+                                        bluetoothScoRequestOwnerAttributionSource(),
+                                        "setNewModeOwner");
                             }
                         }
                     }
@@ -2029,10 +2060,12 @@
                     }
                     break;
 
-                case MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT:
+                case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            onUpdateCommunicationRouteClient(msg.arg1, (String) msg.obj);
+                            UpdateCommRouteClientInfo info = (UpdateCommRouteClientInfo) msg.obj;
+                            onUpdateCommunicationRouteClient(
+                                    info.attributionSource, info.eventSource);
                         }
                     }
                     break;
@@ -2182,7 +2215,7 @@
     private static final int MSG_REPORT_NEW_ROUTES_A2DP = 36;
 
     private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
-    private static final int MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
+    private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
 
     private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
     //
@@ -2394,20 +2427,20 @@
 
     private class CommunicationRouteClient implements IBinder.DeathRecipient {
         private final IBinder mCb;
-        private final int mUid;
+        @NonNull private final AttributionSource mAttributionSource;
         private final boolean mIsPrivileged;
         private AudioDeviceAttributes mDevice;
         private boolean mPlaybackActive;
         private boolean mRecordingActive;
 
-        CommunicationRouteClient(IBinder cb, int uid, AudioDeviceAttributes device,
-                                 boolean isPrivileged) {
+        CommunicationRouteClient(IBinder cb, @NonNull AttributionSource attributionSource,
+                AudioDeviceAttributes device, boolean isPrivileged) {
             mCb = cb;
-            mUid = uid;
+            mAttributionSource = attributionSource;
             mDevice = device;
             mIsPrivileged = isPrivileged;
-            mPlaybackActive = mAudioService.isPlaybackActiveForUid(uid);
-            mRecordingActive = mAudioService.isRecordingActiveForUid(uid);
+            mPlaybackActive = mAudioService.isPlaybackActiveForUid(attributionSource.getUid());
+            mRecordingActive = mAudioService.isRecordingActiveForUid(attributionSource.getUid());
         }
 
         public boolean registerDeathRecipient() {
@@ -2438,8 +2471,12 @@
             return mCb;
         }
 
+        @NonNull AttributionSource getAttributionSource() {
+            return mAttributionSource;
+        }
+
         int getUid() {
-            return mUid;
+            return mAttributionSource.getUid();
         }
 
         boolean isPrivileged() {
@@ -2464,7 +2501,7 @@
 
         @Override
         public String toString() {
-            return "[CommunicationRouteClient: mUid: " + mUid
+            return "[CommunicationRouteClient: mAttributionSource: " + mAttributionSource
                     + " mDevice: " + mDevice.toString()
                     + " mIsPrivileged: " + mIsPrivileged
                     + " mPlaybackActive: " + mPlaybackActive
@@ -2479,8 +2516,8 @@
             return;
         }
         Log.w(TAG, "Communication client died");
-        setCommunicationRouteForClient(client.getBinder(), client.getUid(), null,
-                BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(),
+        setCommunicationRouteForClient(client.getBinder(), client.getAttributionSource(),
+                null, BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(),
                 "onCommunicationRouteClientDied");
     }
 
@@ -2561,21 +2598,22 @@
     // @GuardedBy("mSetModeLock")
     @GuardedBy("mDeviceStateLock")
     private void onUpdateCommunicationRouteClient(
-            int previousBtScoRequesterUid, String eventSource) {
+            @Nullable AttributionSource previousBtScoRequesterAS, String eventSource) {
         CommunicationRouteClient crc = topCommunicationRouteClient();
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
-                    + " previousBtScoRequesterUid: " + previousBtScoRequesterUid
+                    + " previous BT SCO Requester UID: "
+                    + safeUidFromAttributionSource(previousBtScoRequesterAS)
                     + " eventSource: " + eventSource);
         }
         if (crc != null) {
-            setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
-                    BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
+            setCommunicationRouteForClient(crc.getBinder(), crc.getAttributionSource(),
+                    crc.getDevice(), BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
         } else {
-            boolean wasScoRequested = previousBtScoRequesterUid != -1;
+            boolean wasScoRequested = previousBtScoRequesterAS != null;
             if (!isBluetoothScoRequested() && wasScoRequested) {
                 if (mScoManagedByAudio) {
-                    if (shouldStartScoForUid(previousBtScoRequesterUid)) {
+                    if (shouldStartScoForAttributionSource(previousBtScoRequesterAS)) {
                         mBtHelper.stopBluetoothSco(eventSource);
                     }
                     setBluetoothScoOn(false, eventSource);
@@ -2624,12 +2662,13 @@
     }
 
     @GuardedBy("mDeviceStateLock")
-    private CommunicationRouteClient addCommunicationRouteClient(IBinder cb, int uid,
-                AudioDeviceAttributes device, boolean isPrivileged) {
+    private CommunicationRouteClient addCommunicationRouteClient(
+            IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device,
+            boolean isPrivileged) {
         // always insert new request at first position
         removeCommunicationRouteClient(cb, true);
         CommunicationRouteClient client =
-                new CommunicationRouteClient(cb, uid, device, isPrivileged);
+                new CommunicationRouteClient(cb, attributionSource, device, isPrivileged);
         if (client.registerDeathRecipient()) {
             mCommunicationRouteClients.add(0, client);
             if (!client.isActive()) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index fdf7dec..37a2fba 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -69,6 +69,7 @@
 import static com.android.media.audio.Flags.equalScoLeaVcIndexRange;
 import static com.android.media.audio.Flags.replaceStreamBtSco;
 import static com.android.media.audio.Flags.ringerModeAffectsAlarm;
+import static com.android.media.audio.Flags.ringMyCar;
 import static com.android.media.audio.Flags.setStreamVolumeOrder;
 import static com.android.media.audio.Flags.vgsVssSyncMuteOrder;
 import static com.android.server.audio.SoundDoseHelper.ACTION_CHECK_MUSIC_ACTIVE;
@@ -761,7 +762,7 @@
 
     /** Streams that can be muted by system. Do not resolve to aliases when checking.
      * @see System#MUTE_STREAMS_AFFECTED */
-    private int mMuteAffectedStreams;
+    protected int mMuteAffectedStreams;
 
     /** Streams that can be muted by user. Do not resolve to aliases when checking.
      * @see System#MUTE_STREAMS_AFFECTED */
@@ -1465,7 +1466,8 @@
 
         mPlaybackMonitor =
                 new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM],
-                        device -> onMuteAwaitConnectionTimeout(device));
+                        device -> onMuteAwaitConnectionTimeout(device),
+                        stream -> isStreamMute(stream));
         mPlaybackMonitor.registerPlaybackCallback(mPlaybackActivityMonitor, true);
 
         mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
@@ -4846,6 +4848,8 @@
                 + replaceStreamBtSco());
         pw.println("\tcom.android.media.audio.equalScoLeaVcIndexRange:"
                 + equalScoLeaVcIndexRange());
+        pw.println("\tcom.android.media.audio.ringMyCar:"
+                + ringMyCar());
     }
 
     private void dumpAudioMode(PrintWriter pw) {
@@ -6840,9 +6844,13 @@
      * @see AudioManager#setCommunicationDevice(int)
      * @see AudioManager#clearCommunicationDevice()
      */
-    public boolean setCommunicationDevice(IBinder cb, int portId) {
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
+    public boolean setCommunicationDevice(IBinder cb, int portId,
+            @NonNull AttributionSource attributionSource) {
+        if (attributionSource == null) {
+            return false;
+        }
+        final int uid = attributionSource.getUid();
+        final int pid = attributionSource.getPid();
 
         AudioDeviceInfo device = null;
         if (portId != 0) {
@@ -6892,7 +6900,8 @@
                 == PackageManager.PERMISSION_GRANTED;
         final long ident = Binder.clearCallingIdentity();
         try {
-            return mDeviceBroker.setCommunicationDevice(cb, uid, device, isPrivileged, eventSource);
+            return mDeviceBroker.setCommunicationDevice(
+                    cb, attributionSource, device, isPrivileged, eventSource);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -6934,7 +6943,11 @@
     }
 
     /** @see AudioManager#setSpeakerphoneOn(boolean) */
-    public void setSpeakerphoneOn(IBinder cb, boolean on) {
+    public void setSpeakerphoneOn(IBinder cb, boolean on,
+            @NonNull AttributionSource attributionSource) {
+        if (attributionSource == null) {
+            return;
+        }
         if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
             return;
         }
@@ -6942,8 +6955,8 @@
                 == PackageManager.PERMISSION_GRANTED;
 
         // for logging only
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
+        final int uid = attributionSource.getUid();
+        final int pid = attributionSource.getPid();
 
         final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
                 .append(") from u/pid:").append(uid).append("/")
@@ -6958,7 +6971,7 @@
 
         final long ident = Binder.clearCallingIdentity();
         try {
-            mDeviceBroker.setSpeakerphoneOn(cb, uid, on, isPrivileged, eventSource);
+            mDeviceBroker.setSpeakerphoneOn(cb, attributionSource, on, isPrivileged, eventSource);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7062,13 +7075,17 @@
     }
 
     /** @see AudioManager#startBluetoothSco() */
-    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+    public void startBluetoothSco(IBinder cb, int targetSdkVersion,
+            @NonNull AttributionSource attributionSource) {
+        if (attributionSource == null) {
+            return;
+        }
         if (!checkAudioSettingsPermission("startBluetoothSco()")) {
             return;
         }
 
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
+        final int uid = attributionSource.getUid();
+        final int pid = attributionSource.getPid();
         final int scoAudioMode =
                 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
                         BtHelper.SCO_MODE_VIRTUAL_CALL : BtHelper.SCO_MODE_UNDEFINED;
@@ -7083,18 +7100,22 @@
                 .set(MediaMetrics.Property.SCO_AUDIO_MODE,
                         BtHelper.scoAudioModeToString(scoAudioMode))
                 .record();
-        startBluetoothScoInt(cb, uid, scoAudioMode, eventSource);
+        startBluetoothScoInt(cb, attributionSource, scoAudioMode, eventSource);
 
     }
 
     /** @see AudioManager#startBluetoothScoVirtualCall() */
-    public void startBluetoothScoVirtualCall(IBinder cb) {
+    public void startBluetoothScoVirtualCall(IBinder cb,
+            @NonNull AttributionSource attributionSource) {
+        if (attributionSource == null) {
+            return;
+        }
         if (!checkAudioSettingsPermission("startBluetoothScoVirtualCall()")) {
             return;
         }
 
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
+        final int uid = attributionSource.getUid();
+        final int pid = attributionSource.getPid();
         final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()")
                 .append(") from u/pid:").append(uid).append("/")
                 .append(pid).toString();
@@ -7106,10 +7127,11 @@
                 .set(MediaMetrics.Property.SCO_AUDIO_MODE,
                         BtHelper.scoAudioModeToString(BtHelper.SCO_MODE_VIRTUAL_CALL))
                 .record();
-        startBluetoothScoInt(cb, uid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource);
+        startBluetoothScoInt(cb, attributionSource, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource);
     }
 
-    void startBluetoothScoInt(IBinder cb, int uid, int scoAudioMode, @NonNull String eventSource) {
+    void startBluetoothScoInt(IBinder cb, AttributionSource attributionSource,
+            int scoAudioMode, @NonNull String eventSource) {
         MediaMetrics.Item mmi = new MediaMetrics.Item(MediaMetrics.Name.AUDIO_BLUETOOTH)
                 .set(MediaMetrics.Property.EVENT, "startBluetoothScoInt")
                 .set(MediaMetrics.Property.SCO_AUDIO_MODE,
@@ -7125,7 +7147,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             mDeviceBroker.startBluetoothScoForClient(
-                    cb, uid, scoAudioMode, isPrivileged, eventSource);
+                    cb, attributionSource, scoAudioMode, isPrivileged, eventSource);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7133,13 +7155,17 @@
     }
 
     /** @see AudioManager#stopBluetoothSco() */
-    public void stopBluetoothSco(IBinder cb){
+    public void stopBluetoothSco(IBinder cb,
+            @NonNull AttributionSource attributionSource) {
+        if (attributionSource == null) {
+            return;
+        }
         if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
                 !mSystemReady) {
             return;
         }
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
+        final int uid = attributionSource.getUid();
+        final int pid = attributionSource.getPid();
         final String eventSource =  new StringBuilder("stopBluetoothSco()")
                 .append(") from u/pid:").append(uid).append("/")
                 .append(pid).toString();
@@ -7147,7 +7173,8 @@
                 == PackageManager.PERMISSION_GRANTED;
         final long ident = Binder.clearCallingIdentity();
         try {
-            mDeviceBroker.stopBluetoothScoForClient(cb, uid, isPrivileged, eventSource);
+            mDeviceBroker.stopBluetoothScoForClient(
+                    cb, attributionSource, isPrivileged, eventSource);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -8672,9 +8699,14 @@
             // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
             // This allows RX path muting by the audio HAL only when explicitly muted but not when
             // index is just set to 0 to repect BT requirements
+            boolean muted = false;
             if (mHasValidStreamType && isVssMuteBijective(mPublicStreamType)
                     && getVssForStreamOrDefault(mPublicStreamType).isFullyMuted()) {
-                index = 0;
+                if (ringMyCar()) {
+                    muted = true;
+                } else {
+                    index = 0;
+                }
             } else if (isStreamBluetoothSco(mPublicStreamType) && index == 0) {
                 index = 1;
             }
@@ -8684,13 +8716,14 @@
                         / getVssForStreamOrDefault(mPublicStreamType).getIndexStepFactor());
             }
 
+
             if (DEBUG_VOL) {
                 Log.d(TAG, "setVolumeIndexInt(" + mAudioVolumeGroup.getId() + ", " + index + ", "
-                        + device + ")");
+                        + muted + ", " + device + ")");
             }
 
             // Set the volume index
-            mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
+            mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, muted, device);
         }
 
         @GuardedBy("AudioService.VolumeStreamState.class")
@@ -9274,6 +9307,13 @@
             }
         }
 
+        /**
+         * Sends the new volume index on the given device to native.
+         *
+         * <p>Make sure the index is consistent with the muting state. When ringMyCar is enabled
+         * will send the non-zero index together with muted state. Otherwise, index 0  will be sent
+         * to native for signalising a muted stream.
+         **/
         @GuardedBy("VolumeStreamState.class")
         private void setStreamVolumeIndex(int index, int device) {
             // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
@@ -9288,18 +9328,19 @@
                         / 10;
             }
 
+            boolean muted = ringMyCar() ? isFullyMuted() : false;
             if (DEBUG_VOL) {
-                Log.d(TAG, "setStreamVolumeIndexAS(" + mStreamType + ", " + index + ", " + device
-                        + ")");
+                Log.d(TAG, "setStreamVolumeIndexAS(streamType=" + mStreamType + ", index=" + index
+                        + ", muted=" + muted + ", device=" + device + ")");
             }
-            mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
+            mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, muted, device);
         }
 
         // must be called while synchronized VolumeStreamState.class
         @GuardedBy("VolumeStreamState.class")
         /*package*/ void applyDeviceVolume_syncVSS(int device) {
             int index;
-            if (isFullyMuted()) {
+            if (isFullyMuted() && !ringMyCar()) {
                 index = 0;
             } else if (isAbsoluteVolumeDevice(device)
                     || isA2dpAbsoluteVolumeDevice(device)
@@ -9333,7 +9374,7 @@
                 for (int i = 0; i < mIndexMap.size(); i++) {
                     final int device = mIndexMap.keyAt(i);
                     if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
-                        if (isFullyMuted()) {
+                        if (isFullyMuted() && !ringMyCar()) {
                             index = 0;
                         } else if (isAbsoluteVolumeDevice(device)
                                 || isA2dpAbsoluteVolumeDevice(device)
@@ -9368,7 +9409,7 @@
                 }
                 // apply default volume last: by convention , default device volume will be used
                 // by audio policy manager if no explicit volume is present for a given device type
-                if (isFullyMuted()) {
+                if (isFullyMuted() && !ringMyCar()) {
                     index = 0;
                 } else {
                     index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 5cabdde..e86c34c 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -547,13 +547,14 @@
      * @param device
      * @return
      */
-    public int setStreamVolumeIndexAS(int stream, int index, int device) {
-        return AudioSystem.setStreamVolumeIndexAS(stream, index, device);
+    public int setStreamVolumeIndexAS(int stream, int index, boolean muted, int device) {
+        return AudioSystem.setStreamVolumeIndexAS(stream, index, muted, device);
     }
 
     /** Same as {@link AudioSystem#setVolumeIndexForAttributes(AudioAttributes, int, int)} */
-    public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, int device) {
-        return AudioSystem.setVolumeIndexForAttributes(attributes, index, device);
+    public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, boolean muted,
+            int device) {
+        return AudioSystem.setVolumeIndexForAttributes(attributes, index, muted, device);
     }
 
     /**
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index a734e73..b63b07f 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -72,6 +72,7 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * Class to receive and dispatch updates from AudioSystem about recording configurations.
@@ -160,18 +161,22 @@
 
     private final Context mContext;
     private int mSavedAlarmVolume = -1;
+    private boolean mSavedAlarmMuted = false;
+    private final Function<Integer, Boolean> mIsStreamMutedCb;
     private final int mMaxAlarmVolume;
     private int mPrivilegedAlarmActiveCount = 0;
     private final Consumer<AudioDeviceAttributes> mMuteAwaitConnectionTimeoutCb;
     private final FadeOutManager mFadeOutManager = new FadeOutManager();
 
     PlaybackActivityMonitor(Context context, int maxAlarmVolume,
-            Consumer<AudioDeviceAttributes> muteTimeoutCallback) {
+            Consumer<AudioDeviceAttributes> muteTimeoutCallback,
+            Function<Integer, Boolean> isStreamMutedCb) {
         mContext = context;
         mMaxAlarmVolume = maxAlarmVolume;
         PlayMonitorClient.sListenerDeathMonitor = this;
         AudioPlaybackConfiguration.sPlayerDeathMonitor = this;
         mMuteAwaitConnectionTimeoutCb = muteTimeoutCallback;
+        mIsStreamMutedCb = isStreamMutedCb;
         initEventHandler();
     }
 
@@ -332,8 +337,9 @@
                     if (mPrivilegedAlarmActiveCount++ == 0) {
                         mSavedAlarmVolume = AudioSystem.getStreamVolumeIndex(
                                 AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER);
+                        mSavedAlarmMuted = mIsStreamMutedCb.apply(AudioSystem.STREAM_ALARM);
                         AudioSystem.setStreamVolumeIndexAS(AudioSystem.STREAM_ALARM,
-                                mMaxAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
+                                mMaxAlarmVolume, /*muted=*/false, AudioSystem.DEVICE_OUT_SPEAKER);
                     }
                 } else if (event != AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
                         apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
@@ -342,7 +348,8 @@
                                 AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER) ==
                                 mMaxAlarmVolume) {
                             AudioSystem.setStreamVolumeIndexAS(AudioSystem.STREAM_ALARM,
-                                    mSavedAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
+                                    mSavedAlarmVolume, mSavedAlarmMuted,
+                                    AudioSystem.DEVICE_OUT_SPEAKER);
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index 1ea72d7..f66c7e1 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -36,6 +36,7 @@
 import android.util.Slog;
 
 import com.android.server.backup.Flags;
+import com.android.server.notification.NotificationBackupHelper;
 
 import com.google.android.collect.Sets;
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index acf4db3..0807c70 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -292,6 +292,13 @@
      */
     public float renderFrameRate;
 
+
+    /**
+     * If {@code true}, this Display supports adaptive refresh rates.
+     * @see android.view.DisplayInfo#hasArrSupport for more details.
+     */
+    public boolean hasArrSupport;
+
     /**
      * The default mode of the display.
      */
@@ -540,7 +547,8 @@
                 other.brightnessDefault)
                 || !Objects.equals(roundedCorners, other.roundedCorners)
                 || installOrientation != other.installOrientation
-                || !Objects.equals(displayShape, other.displayShape)) {
+                || !Objects.equals(displayShape, other.displayShape)
+                || hasArrSupport != other.hasArrSupport) {
             diff |= DIFF_OTHER;
         }
         return diff;
@@ -558,6 +566,7 @@
         height = other.height;
         modeId = other.modeId;
         renderFrameRate = other.renderFrameRate;
+        hasArrSupport = other.hasArrSupport;
         defaultModeId = other.defaultModeId;
         userPreferredModeId = other.userPreferredModeId;
         supportedModes = other.supportedModes;
@@ -602,6 +611,7 @@
         sb.append(width).append(" x ").append(height);
         sb.append(", modeId ").append(modeId);
         sb.append(", renderFrameRate ").append(renderFrameRate);
+        sb.append(", hasArrSupport ").append(hasArrSupport);
         sb.append(", defaultModeId ").append(defaultModeId);
         sb.append(", userPreferredModeId ").append(userPreferredModeId);
         sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5edea0a..f9c3a46 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -246,6 +246,7 @@
         private int mActiveModeId = INVALID_MODE_ID;
         private boolean mDisplayModeSpecsInvalid;
         private int mActiveColorMode;
+        private boolean mHasArrSupport;
         private Display.HdrCapabilities mHdrCapabilities;
         private boolean mAllmSupported;
         private boolean mGameContentTypeSupported;
@@ -311,6 +312,7 @@
             changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities);
             changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported);
             changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported);
+            changed |= updateHasArrSupportLocked(dynamicInfo.hasArrSupport);
 
             if (changed) {
                 mHavePendingChanges = true;
@@ -602,6 +604,14 @@
             return true;
         }
 
+        private boolean updateHasArrSupportLocked(boolean newHasArrSupport) {
+            if (mHasArrSupport == newHasArrSupport) {
+                return false;
+            }
+            mHasArrSupport = newHasArrSupport;
+            return true;
+        }
+
         private boolean updateAllmSupport(boolean supported) {
             if (mAllmSupported == supported) {
                 return false;
@@ -684,6 +694,7 @@
                     mInfo.supportedColorModes[i] = mSupportedColorModes.get(i);
                 }
                 mInfo.hdrCapabilities = mHdrCapabilities;
+                mInfo.hasArrSupport = mHasArrSupport;
                 mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
                 mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
                 mInfo.state = mState;
@@ -1274,6 +1285,7 @@
             pw.println("mActiveColorMode=" + mActiveColorMode);
             pw.println("mDefaultModeId=" + mDefaultModeId);
             pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
+            pw.println("mHasArrSupport=" + mHasArrSupport);
             pw.println("mState=" + Display.stateToString(mState));
             pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
             pw.println("mBrightnessState=" + mBrightnessState);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 007e3a8..074a4d8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -506,12 +506,13 @@
             mBaseDisplayInfo.rotation = Surface.ROTATION_0;
             mBaseDisplayInfo.modeId = deviceInfo.modeId;
             mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate;
+            mBaseDisplayInfo.hasArrSupport = deviceInfo.hasArrSupport;
             mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
             mBaseDisplayInfo.userPreferredModeId = deviceInfo.userPreferredModeId;
             mBaseDisplayInfo.supportedModes = Arrays.copyOf(
                     deviceInfo.supportedModes, deviceInfo.supportedModes.length);
             mBaseDisplayInfo.appsSupportedModes = syntheticModeManager.createAppSupportedModes(
-                    config, mBaseDisplayInfo.supportedModes
+                    config, mBaseDisplayInfo.supportedModes, mBaseDisplayInfo.hasArrSupport
             );
             mBaseDisplayInfo.colorMode = deviceInfo.colorMode;
             mBaseDisplayInfo.supportedColorModes = Arrays.copyOf(
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index 9a0ee03..a4804e1 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -50,8 +50,10 @@
     public static final int MODIFIER_THROTTLED = 0x8;
     public static final int MODIFIER_MIN_LUX = 0x10;
     public static final int MODIFIER_MIN_USER_SET_LOWER_BOUND = 0x20;
+    public static final int MODIFIER_STYLUS_UNDER_USE = 0x40;
     public static final int MODIFIER_MASK = MODIFIER_DIMMED | MODIFIER_LOW_POWER | MODIFIER_HDR
-            | MODIFIER_THROTTLED | MODIFIER_MIN_LUX | MODIFIER_MIN_USER_SET_LOWER_BOUND;
+            | MODIFIER_THROTTLED | MODIFIER_MIN_LUX | MODIFIER_MIN_USER_SET_LOWER_BOUND
+            | MODIFIER_STYLUS_UNDER_USE;
 
     // ADJUSTMENT_*
     // These things can happen at any point, even if the main brightness reason doesn't
@@ -158,6 +160,9 @@
         if ((mModifier & MODIFIER_MIN_USER_SET_LOWER_BOUND) != 0) {
             sb.append(" user_min_pref");
         }
+        if ((mModifier & MODIFIER_STYLUS_UNDER_USE) != 0) {
+            sb.append(" stylus_under_use");
+        }
         int strlen = sb.length();
         if (sb.charAt(strlen - 1) == '[') {
             sb.setLength(strlen - 2);
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 71fdaf3..4bd9808 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -110,6 +110,9 @@
     @VisibleForTesting
     AutomaticBrightnessController mAutomaticBrightnessController;
 
+    // True if the stylus is being used
+    private boolean mIsStylusBeingUsed;
+
     /**
      * The constructor of DisplayBrightnessController.
      */
@@ -460,6 +463,8 @@
         writer.println("  mScreenBrightnessDefault=" + mScreenBrightnessDefault);
         writer.println("  mPersistBrightnessNitsForDefaultDisplay="
                 + mPersistBrightnessNitsForDefaultDisplay);
+        writer.println("  mIsStylusBeingUsed="
+                + mIsStylusBeingUsed);
         synchronized (mLock) {
             writer.println("  mPendingScreenBrightness=" + mPendingScreenBrightness);
             writer.println("  mCurrentScreenBrightness=" + mCurrentScreenBrightness);
@@ -505,7 +510,12 @@
      * Notifies if the stylus is currently being used or not.
      */
     public void setStylusBeingUsed(boolean isEnabled) {
-        // Todo(b/369977976) - Disable the auto-brightness strategy
+        mIsStylusBeingUsed = isEnabled;
+    }
+
+    @VisibleForTesting
+    boolean isStylusBeingUsed() {
+        return mIsStylusBeingUsed;
     }
 
     @VisibleForTesting
@@ -626,13 +636,14 @@
             lastUserSetScreenBrightness = mLastUserSetScreenBrightness;
         }
         return new StrategySelectionRequest(displayPowerRequest, targetDisplayState,
-                lastUserSetScreenBrightness, userSetBrightnessChanged, displayOffloadSession);
+                lastUserSetScreenBrightness, userSetBrightnessChanged, displayOffloadSession,
+                mIsStylusBeingUsed);
     }
 
     private StrategyExecutionRequest constructStrategyExecutionRequest(
             DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
         float currentScreenBrightness = getCurrentBrightness();
         return new StrategyExecutionRequest(displayPowerRequest, currentScreenBrightness,
-                mUserSetScreenBrightnessUpdated);
+                mUserSetScreenBrightnessUpdated, mIsStylusBeingUsed);
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 06890e7..ded7447 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -306,7 +306,8 @@
                 strategySelectionRequest.getDisplayPowerRequest().useNormalBrightnessForDoze,
                 strategySelectionRequest.getLastUserSetScreenBrightness(),
                 strategySelectionRequest.isUserSetBrightnessChanged());
-        return mAutomaticBrightnessStrategy1.isAutoBrightnessValid();
+        return !strategySelectionRequest.isStylusBeingUsed()
+                && mAutomaticBrightnessStrategy1.isAutoBrightnessValid();
     }
 
     private StrategySelectionNotifyRequest constructStrategySelectionNotifyRequest(
diff --git a/services/core/java/com/android/server/display/brightness/StrategyExecutionRequest.java b/services/core/java/com/android/server/display/brightness/StrategyExecutionRequest.java
index 304640b..7a07c4f 100644
--- a/services/core/java/com/android/server/display/brightness/StrategyExecutionRequest.java
+++ b/services/core/java/com/android/server/display/brightness/StrategyExecutionRequest.java
@@ -32,11 +32,15 @@
     // Represents if the user set screen brightness was changed or not.
     private boolean mUserSetBrightnessChanged;
 
+    private boolean mIsStylusBeingUsed;
+
     public StrategyExecutionRequest(DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
-            float currentScreenBrightness, boolean userSetBrightnessChanged) {
+            float currentScreenBrightness, boolean userSetBrightnessChanged,
+            boolean isStylusBeingUsed) {
         mDisplayPowerRequest = displayPowerRequest;
         mCurrentScreenBrightness = currentScreenBrightness;
         mUserSetBrightnessChanged = userSetBrightnessChanged;
+        mIsStylusBeingUsed = isStylusBeingUsed;
     }
 
     public DisplayManagerInternal.DisplayPowerRequest getDisplayPowerRequest() {
@@ -51,6 +55,10 @@
         return mUserSetBrightnessChanged;
     }
 
+    public boolean isStylusBeingUsed() {
+        return mIsStylusBeingUsed;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof StrategyExecutionRequest)) {
@@ -59,12 +67,13 @@
         StrategyExecutionRequest other = (StrategyExecutionRequest) obj;
         return Objects.equals(mDisplayPowerRequest, other.getDisplayPowerRequest())
                 && mCurrentScreenBrightness == other.getCurrentScreenBrightness()
-                && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged();
+                && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged()
+                && mIsStylusBeingUsed == other.isStylusBeingUsed();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mDisplayPowerRequest, mCurrentScreenBrightness,
-                mUserSetBrightnessChanged);
+                mUserSetBrightnessChanged, mIsStylusBeingUsed);
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java b/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java
index aa2f23e..5c1f03d 100644
--- a/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java
+++ b/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java
@@ -40,15 +40,19 @@
 
     private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession;
 
+    private boolean mIsStylusBeingUsed;
+
     public StrategySelectionRequest(DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
             int targetDisplayState, float lastUserSetScreenBrightness,
             boolean userSetBrightnessChanged,
-            DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) {
+            DisplayManagerInternal.DisplayOffloadSession displayOffloadSession,
+            boolean isStylusBeingUsed) {
         mDisplayPowerRequest = displayPowerRequest;
         mTargetDisplayState = targetDisplayState;
         mLastUserSetScreenBrightness = lastUserSetScreenBrightness;
         mUserSetBrightnessChanged = userSetBrightnessChanged;
         mDisplayOffloadSession = displayOffloadSession;
+        mIsStylusBeingUsed = isStylusBeingUsed;
     }
 
     public DisplayManagerInternal.DisplayPowerRequest getDisplayPowerRequest() {
@@ -72,6 +76,10 @@
         return mDisplayOffloadSession;
     }
 
+    public boolean isStylusBeingUsed() {
+        return mIsStylusBeingUsed;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof StrategySelectionRequest)) {
@@ -82,12 +90,14 @@
                 && mTargetDisplayState == other.getTargetDisplayState()
                 && mLastUserSetScreenBrightness == other.getLastUserSetScreenBrightness()
                 && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged()
-                && mDisplayOffloadSession.equals(other.getDisplayOffloadSession());
+                && mDisplayOffloadSession.equals(other.getDisplayOffloadSession())
+                && mIsStylusBeingUsed == other.isStylusBeingUsed();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mDisplayPowerRequest, mTargetDisplayState,
-                mLastUserSetScreenBrightness, mUserSetBrightnessChanged, mDisplayOffloadSession);
+                mLastUserSetScreenBrightness, mUserSetBrightnessChanged, mDisplayOffloadSession,
+                mIsStylusBeingUsed);
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
index 7c0c931..b9de34a 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
@@ -37,6 +37,9 @@
             StrategyExecutionRequest strategyExecutionRequest) {
         BrightnessReason brightnessReason = new BrightnessReason();
         brightnessReason.setReason(BrightnessReason.REASON_MANUAL);
+        if (strategyExecutionRequest.isStylusBeingUsed()) {
+            brightnessReason.setModifier(BrightnessReason.MODIFIER_STYLUS_UNDER_USE);
+        }
         return new DisplayBrightnessState.Builder()
                 .setBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
                 .setBrightnessReason(brightnessReason)
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 70bf566..07343f4 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -232,6 +232,11 @@
             Flags::enableBatteryStatsForAllDisplays
     );
 
+    private final FlagState mHasArrSupport = new FlagState(
+            Flags.FLAG_ENABLE_HAS_ARR_SUPPORT,
+            Flags::enableHasArrSupport
+    );
+
     /**
      * @return {@code true} if 'port' is allowed in display layout configuration file.
      */
@@ -493,6 +498,12 @@
     }
 
     /**
+     * @return {@code true} if hasArrSupport API is enabled.
+     */
+    public boolean hasArrSupportFlag() {
+        return mHasArrSupport.isEnabled();
+    }
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
@@ -541,6 +552,7 @@
         pw.println(" " + mEnableApplyDisplayChangedDuringDisplayAdded);
         pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage);
         pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
+        pw.println(" " + mHasArrSupport);
     }
 
     private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 602c699..ddb2969 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -414,3 +414,11 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_has_arr_support"
+    namespace: "core_graphics"
+    description: "Flag for an API to get whether display supports ARR or not"
+    bug: "361433651"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index ffa64bf..88562ab 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -156,6 +156,8 @@
     // a map from display id to display device config
     private SparseArray<DisplayDeviceConfig> mDisplayDeviceConfigByDisplay = new SparseArray<>();
 
+    private SparseBooleanArray mHasArrSupport;
+
     private BrightnessObserver mBrightnessObserver;
 
     private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
@@ -194,6 +196,8 @@
 
     private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
 
+    private final boolean mHasArrSupportFlagEnabled;
+
     private final DisplayManagerFlags mDisplayManagerFlags;
 
     private final DisplayDeviceConfigProvider mDisplayDeviceConfigProvider;
@@ -218,6 +222,7 @@
             .isDisplaysRefreshRatesSynchronizationEnabled();
         mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
                 .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
+        mHasArrSupportFlagEnabled = displayManagerFlags.hasArrSupportFlag();
         mDisplayManagerFlags = displayManagerFlags;
         mDisplayDeviceConfigProvider = displayDeviceConfigProvider;
         mContext = context;
@@ -228,6 +233,7 @@
         mSupportedModesByDisplay = new SparseArray<>();
         mAppSupportedModesByDisplay = new SparseArray<>();
         mDefaultModeByDisplay = new SparseArray<>();
+        mHasArrSupport = new SparseBooleanArray();
         mAppRequestObserver = new AppRequestObserver(displayManagerFlags);
         mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig());
         mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
@@ -452,7 +458,13 @@
         return mAppRequestObserver;
     }
 
+    // TODO(b/372019752) Rename all the occurrences of the VRR with ARR.
     private boolean isVrrSupportedLocked(int displayId) {
+        if (mHasArrSupportFlagEnabled) {
+            Boolean hasArrSupport = mHasArrSupport.get(displayId);
+            return hasArrSupport != null && hasArrSupport;
+        }
+        // TODO(b/371041638) Remove config.isVrrSupportEnabled once hasArrSupport is rolled out
         DisplayDeviceConfig config = mDisplayDeviceConfigByDisplay.get(displayId);
         return config != null && config.isVrrSupportEnabled();
     }
@@ -1469,6 +1481,7 @@
             DisplayInfo displayInfo = getDisplayInfo(displayId);
             registerExternalDisplay(displayInfo);
             updateDisplayModes(displayId, displayInfo);
+            updateHasArrSupport(displayId, displayInfo);
             updateLayoutLimitedFrameRate(displayId, displayInfo);
             updateUserSettingDisplayPreferredSize(displayInfo);
             updateDisplaysPeakRefreshRateAndResolution(displayInfo);
@@ -1482,6 +1495,7 @@
                 mDefaultModeByDisplay.remove(displayId);
                 mDisplayDeviceConfigByDisplay.remove(displayId);
                 mSettingsObserver.removeRefreshRateSetting(displayId);
+                mHasArrSupport.delete(displayId);
             }
             updateLayoutLimitedFrameRate(displayId, null);
             removeUserSettingDisplayPreferredSize(displayId);
@@ -1493,6 +1507,7 @@
         public void onDisplayChanged(int displayId) {
             updateDisplayDeviceConfig(displayId);
             DisplayInfo displayInfo = getDisplayInfo(displayId);
+            updateHasArrSupport(displayId, displayInfo);
             updateDisplayModes(displayId, displayInfo);
             updateLayoutLimitedFrameRate(displayId, displayInfo);
             updateUserSettingDisplayPreferredSize(displayInfo);
@@ -1691,6 +1706,16 @@
                 }
             }
         }
+
+        private void updateHasArrSupport(int displayId, @Nullable DisplayInfo info) {
+            if (info == null) {
+                return;
+            }
+            synchronized (mLock) {
+                mHasArrSupport.put(displayId, info.hasArrSupport);
+            }
+        }
+
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/mode/SyntheticModeManager.java b/services/core/java/com/android/server/display/mode/SyntheticModeManager.java
index a83b939..71b34679 100644
--- a/services/core/java/com/android/server/display/mode/SyntheticModeManager.java
+++ b/services/core/java/com/android/server/display/mode/SyntheticModeManager.java
@@ -37,17 +37,22 @@
             SYNTHETIC_MODE_REFRESH_RATE + FLOAT_TOLERANCE;
 
     private final boolean mSynthetic60HzModesEnabled;
+    private final boolean mHasArrSupportEnabled;
 
     public SyntheticModeManager(DisplayManagerFlags flags) {
         mSynthetic60HzModesEnabled = flags.isSynthetic60HzModesEnabled();
+        mHasArrSupportEnabled = flags.hasArrSupportFlag();
     }
 
     /**
      * creates display supportedModes array, exposed to applications
      */
     public Display.Mode[] createAppSupportedModes(DisplayDeviceConfig config,
-            Display.Mode[] modes) {
-        if (!config.isVrrSupportEnabled() || !mSynthetic60HzModesEnabled) {
+            Display.Mode[] modes, boolean hasArrSupport) {
+        // TODO(b/361433651) Remove config.isVrrSupportEnabled once hasArrSupport is rolled out
+        boolean isArrSupported =
+                mHasArrSupportEnabled ? hasArrSupport : config.isVrrSupportEnabled();
+        if (!isArrSupported || !mSynthetic60HzModesEnabled) {
             return modes;
         }
         List<Display.Mode> appSupportedModes = new ArrayList<>();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 939aad4..83044c2 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1536,7 +1536,16 @@
                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         }
         final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
-        return settings.getMethodMap().get(settings.getSelectedInputMethod());
+        final String selectedImeId;
+        if (Flags.consistentGetCurrentInputMethodInfo()) {
+            final var bindingController = getInputMethodBindingController(userId);
+            synchronized (ImfLock.class) {
+                selectedImeId = bindingController.getSelectedMethodId();
+            }
+        } else {
+            selectedImeId = settings.getSelectedInputMethod();
+        }
+        return settings.getMethodMap().get(selectedImeId);
     }
 
     @BinderThread
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index dc2c957..636854b 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -63,7 +63,6 @@
 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
-import com.android.server.integrity.engine.RuleEvaluationEngine;
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.integrity.model.RuleMetadata;
 import com.android.server.pm.PackageManagerServiceUtils;
@@ -130,7 +129,6 @@
     private final Handler mHandler;
     private final PackageManagerInternal mPackageManagerInternal;
     private final Supplier<PackageParser2> mParserSupplier;
-    private final RuleEvaluationEngine mEvaluationEngine;
     private final IntegrityFileManager mIntegrityFileManager;
 
     /** Create an instance of {@link AppIntegrityManagerServiceImpl}. */
@@ -142,7 +140,6 @@
                 context,
                 LocalServices.getService(PackageManagerInternal.class),
                 PackageParserUtils::forParsingFileWithDefaults,
-                RuleEvaluationEngine.getRuleEvaluationEngine(),
                 IntegrityFileManager.getInstance(),
                 handlerThread.getThreadHandler());
     }
@@ -152,13 +149,11 @@
             Context context,
             PackageManagerInternal packageManagerInternal,
             Supplier<PackageParser2> parserSupplier,
-            RuleEvaluationEngine evaluationEngine,
             IntegrityFileManager integrityFileManager,
             Handler handler) {
         mContext = context;
         mPackageManagerInternal = packageManagerInternal;
         mParserSupplier = parserSupplier;
-        mEvaluationEngine = evaluationEngine;
         mIntegrityFileManager = integrityFileManager;
         mHandler = handler;
 
@@ -330,7 +325,7 @@
                                 + " installers "
                                 + allowedInstallers);
             }
-            IntegrityCheckResult result = mEvaluationEngine.evaluate(appInstallMetadata);
+            IntegrityCheckResult result = IntegrityCheckResult.allow();
             if (!result.getMatchedRules().isEmpty() || DEBUG_INTEGRITY_COMPONENT) {
                 Slog.i(
                         TAG,
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
deleted file mode 100644
index e8c828b..0000000
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.engine;
-
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.Rule;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.integrity.IntegrityFileManager;
-import com.android.server.integrity.model.IntegrityCheckResult;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * The engine used to evaluate rules against app installs.
- *
- * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine
- * to allow/block that install.
- */
-public class RuleEvaluationEngine {
-    private static final String TAG = "RuleEvaluation";
-
-    // The engine for loading rules, retrieving metadata for app installs, and evaluating app
-    // installs against rules.
-    private static RuleEvaluationEngine sRuleEvaluationEngine;
-
-    private final IntegrityFileManager mIntegrityFileManager;
-
-    @VisibleForTesting
-    RuleEvaluationEngine(IntegrityFileManager integrityFileManager) {
-        mIntegrityFileManager = integrityFileManager;
-    }
-
-    /** Provide a singleton instance of the rule evaluation engine. */
-    public static synchronized RuleEvaluationEngine getRuleEvaluationEngine() {
-        if (sRuleEvaluationEngine == null) {
-            return new RuleEvaluationEngine(IntegrityFileManager.getInstance());
-        }
-        return sRuleEvaluationEngine;
-    }
-
-    /**
-     * Load, and match the list of rules against an app install metadata.
-     *
-     * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
-     *                           against.
-     * @return result of the integrity check
-     */
-    public IntegrityCheckResult evaluate(
-            AppInstallMetadata appInstallMetadata) {
-        List<Rule> rules = loadRules(appInstallMetadata);
-        return IntegrityCheckResult.allow();
-    }
-
-    private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
-        if (!mIntegrityFileManager.initialized()) {
-            Slog.w(TAG, "Integrity rule files are not available.");
-            return Collections.emptyList();
-        }
-
-        try {
-            return mIntegrityFileManager.readRules(appInstallMetadata);
-        } catch (Exception e) {
-            Slog.e(TAG, "Error loading rules.", e);
-            return new ArrayList<>();
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 741513c..7e80cbc 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -221,7 +221,7 @@
         public void onShellCommand(FileDescriptor in, FileDescriptor out,
                 FileDescriptor err, String[] args, ShellCallback callback,
                 ResultReceiver resultReceiver) {
-            (new LocaleManagerShellCommand(mBinderService))
+            (new LocaleManagerShellCommand(mBinderService, mContext))
                     .exec(this, in, out, err, args, callback, resultReceiver);
         }
 
diff --git a/services/core/java/com/android/server/locales/LocaleManagerShellCommand.java b/services/core/java/com/android/server/locales/LocaleManagerShellCommand.java
index 09f2ffa..926b647 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerShellCommand.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerShellCommand.java
@@ -19,6 +19,8 @@
 import android.app.ActivityManager;
 import android.app.ILocaleManager;
 import android.app.LocaleConfig;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.os.ShellCommand;
@@ -31,9 +33,11 @@
  */
 public class LocaleManagerShellCommand extends ShellCommand {
     private final ILocaleManager mBinderService;
+    private final Context mContext;
 
-    LocaleManagerShellCommand(ILocaleManager localeManager) {
+    LocaleManagerShellCommand(ILocaleManager localeManager, Context context) {
         mBinderService = localeManager;
+        mContext = context;
     }
     @Override
     public int onCommand(String cmd) {
@@ -49,6 +53,8 @@
                 return runSetAppOverrideLocaleConfig();
             case "get-app-localeconfig":
                 return runGetAppOverrideLocaleConfig();
+            case "get-app-localeconfig-ignore-override":
+                return runGetAppLocaleConfigIgnoreOverride();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -261,6 +267,55 @@
         return 0;
     }
 
+    private int runGetAppLocaleConfigIgnoreOverride() {
+        String packageName = getNextArg();
+        final PrintWriter err = getErrPrintWriter();
+
+        if (packageName != null) {
+            int userId = ActivityManager.getCurrentUser();
+            do {
+                String option = getNextOption();
+                if (option == null) {
+                    break;
+                }
+                if ("--user".equals(option)) {
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                } else {
+                    throw new IllegalArgumentException("Unknown option: " + option);
+                }
+            } while (true);
+            LocaleConfig resLocaleConfig = null;
+            try {
+                resLocaleConfig = LocaleConfig.fromContextIgnoringOverride(
+                    mContext.createPackageContextAsUser(packageName, /* flags= */ 0,
+                        UserHandle.of(userId)));
+            } catch (PackageManager.NameNotFoundException e) {
+                err.println("Unknown package name " + packageName + " for user " + userId);
+                return -1;
+            }
+            if (resLocaleConfig == null) {
+                getOutPrintWriter().println(
+                        "LocaleConfig for " + packageName + " for user " + userId + " is null");
+            } else {
+                LocaleList locales = resLocaleConfig.getSupportedLocales();
+                if (locales == null) {
+                    getOutPrintWriter().println(
+                            "Locales within the LocaleConfig for " + packageName + " for user "
+                                    + userId + " are null");
+                } else {
+                    getOutPrintWriter().println(
+                            "Locales within the LocaleConfig for " + packageName + " for user "
+                                    + userId + " are [" + locales.toLanguageTags() + "]");
+                }
+            }
+        } else {
+            err.println("Error: no package specified");
+            return -1;
+        }
+        return 0;
+    }
+
     private LocaleList parseOverrideLocales() {
         String locales = getNextArg();
         if (locales == null) {
diff --git a/services/core/java/com/android/server/media/AudioManagerRouteController.java b/services/core/java/com/android/server/media/AudioManagerRouteController.java
index c79f41d..25e1c94 100644
--- a/services/core/java/com/android/server/media/AudioManagerRouteController.java
+++ b/services/core/java/com/android/server/media/AudioManagerRouteController.java
@@ -420,7 +420,7 @@
         // to derive a name ourselves from the type instead.
         String deviceName = audioDeviceInfo.getPort().name();
 
-        if (!TextUtils.isEmpty(address)) {
+        if (mBluetoothRouteController.containsBondedDeviceWithAddress(address)) {
             routeId = mBluetoothRouteController.getRouteIdForBluetoothAddress(address);
             deviceName = mBluetoothRouteController.getNameForBluetoothAddress(address);
         }
diff --git a/services/core/java/com/android/server/media/BluetoothDeviceRoutesManager.java b/services/core/java/com/android/server/media/BluetoothDeviceRoutesManager.java
index 8b65ea3..c79d6e5 100644
--- a/services/core/java/com/android/server/media/BluetoothDeviceRoutesManager.java
+++ b/services/core/java/com/android/server/media/BluetoothDeviceRoutesManager.java
@@ -141,6 +141,11 @@
         mContext.unregisterReceiver(mDeviceStateChangedReceiver);
     }
 
+    /** Returns true if the given address corresponds to a currently-bonded Bluetooth device. */
+    public synchronized boolean containsBondedDeviceWithAddress(@Nullable String address) {
+        return mAddressToBondedDevice.containsKey(address);
+    }
+
     @Nullable
     public synchronized String getRouteIdForBluetoothAddress(@Nullable String address) {
         BluetoothDevice bluetoothDevice = mAddressToBondedDevice.get(address);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a6f4c0e..2a3be1e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3100,11 +3100,16 @@
         }
 
         synchronized (mUidRulesFirstLock) {
-            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
-            policy |= oldPolicy;
-            if (oldPolicy != policy) {
-                setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
-                mLogger.uidPolicyChanged(uid, oldPolicy, policy);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+                policy |= oldPolicy;
+                if (oldPolicy != policy) {
+                    setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
+                    mLogger.uidPolicyChanged(uid, oldPolicy, policy);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
     }
@@ -3119,11 +3124,16 @@
         }
 
         synchronized (mUidRulesFirstLock) {
-            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
-            policy = oldPolicy & ~policy;
-            if (oldPolicy != policy) {
-                setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
-                mLogger.uidPolicyChanged(uid, oldPolicy, policy);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+                policy = oldPolicy & ~policy;
+                if (oldPolicy != policy) {
+                    setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
+                    mLogger.uidPolicyChanged(uid, oldPolicy, policy);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index cfcf6eb..f186f42 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -32,6 +32,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.PrintWriter;
 import java.util.Date;
 import java.util.Objects;
@@ -296,4 +298,8 @@
         void onChanged();
     }
 
+    @VisibleForTesting // (otherwise = NONE)
+    public int getUserId() {
+        return mUserContext.getUserId();
+    }
 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 66e61c0..0b40d64 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -169,16 +169,15 @@
         for (int i = 0; i < mSystemConditionProviders.size(); i++) {
             mSystemConditionProviders.valueAt(i).onBootComplete();
         }
-        if (mCallback != null) {
-            mCallback.onBootComplete();
-        }
     }
 
     @Override
     public void onUserSwitched(int user) {
         super.onUserSwitched(user);
-        if (mCallback != null) {
-            mCallback.onUserSwitched();
+        if (android.app.Flags.modesHsum()) {
+            for (int i = 0; i < mSystemConditionProviders.size(); i++) {
+                mSystemConditionProviders.valueAt(i).onUserSwitched(UserHandle.of(user));
+            }
         }
     }
 
@@ -515,10 +514,8 @@
     }
 
     public interface Callback {
-        void onBootComplete();
         void onServiceAdded(ComponentName component);
         void onConditionChanged(Uri id, Condition condition);
-        void onUserSwitched();
     }
 
 }
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index c3ace15..bb8ccd2 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
 import android.text.format.DateUtils;
@@ -65,6 +66,11 @@
     }
 
     @Override
+    public void onUserSwitched(UserHandle user) {
+        // Nothing to do because countdown conditions are not tied to any user data.
+    }
+
+    @Override
     public void dump(PrintWriter pw, DumpFilter filter) {
         pw.println("    CountdownConditionProvider:");
         pw.print("      mConnected="); pw.println(mConnected);
diff --git a/services/core/java/com/android/server/notification/CustomManualConditionProvider.java b/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
index 9531c5e..52dc116 100644
--- a/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
@@ -17,6 +17,7 @@
 package com.android.server.notification;
 
 import android.net.Uri;
+import android.os.UserHandle;
 import android.service.notification.ZenModeConfig;
 
 import java.io.PrintWriter;
@@ -40,6 +41,11 @@
     }
 
     @Override
+    public void onUserSwitched(UserHandle user) {
+        // Nothing to do because we won't ever call notifyConditions.
+    }
+
+    @Override
     public void onConnected() {
         // No need to keep subscriptions because we won't ever call notifyConditions
     }
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index 00dd547..ecc4cf7 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -23,6 +24,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -37,6 +39,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.notification.CalendarTracker.CheckEventResult;
 import com.android.server.notification.NotificationManagerService.DumpFilter;
 import com.android.server.pm.PackageManagerService;
@@ -59,12 +62,13 @@
     private static final String EXTRA_TIME = "time";
     private static final long CHANGE_DELAY = 2 * 1000;  // coalesce chatty calendar changes
 
-    private final Context mContext = this;
+    @VisibleForTesting Context mContext = this;
     private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
     private final SparseArray<CalendarTracker> mTrackers = new SparseArray<>();
     private final Handler mWorker;
     private final HandlerThread mThread;
 
+    @Nullable private UserHandle mCurrentUser;
     private boolean mConnected;
     private boolean mRegistered;
     private boolean mBootComplete;  // don't hammer the calendar provider until boot completes.
@@ -114,10 +118,28 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                reloadTrackers();
+                if (android.app.Flags.modesHsum()) {
+                    if (mCurrentUser != null) {
+                        // Possibly the intent signals a profile added on a different user, but it
+                        // doesn't matter (except for a bit of wasted work here). We will reload
+                        // trackers for that user when we switch.
+                        reloadTrackers(mCurrentUser);
+                    }
+                } else {
+                    reloadTrackers();
+                }
             }
         }, filter);
-        reloadTrackers();
+        if (!android.app.Flags.modesHsum()) {
+            reloadTrackers();
+        }
+    }
+
+    @Override
+    public void onUserSwitched(UserHandle user) {
+        if (DEBUG) Slog.d(TAG, "onUserSwitched: " + user);
+        mCurrentUser = user;
+        reloadTrackers(user);
     }
 
     @Override
@@ -157,8 +179,41 @@
         }
     }
 
+    private void reloadTrackers(UserHandle user) {
+        if (DEBUG) Slog.d(TAG, "reloadTrackers user=" + user);
+        for (int i = 0; i < mTrackers.size(); i++) {
+            mTrackers.valueAt(i).setCallback(null);
+        }
+        mTrackers.clear();
+
+        // Ensure that user is the main user and not a profile.
+        UserManager userManager = UserManager.get(mContext);
+        UserHandle possibleParent = userManager.getProfileParent(user);
+        if (possibleParent != null) {
+            Slog.wtf(TAG, "reloadTrackers should not be called with profile " + user
+                    + "; continuing with parent " + possibleParent);
+            user = possibleParent;
+        }
+
+        for (UserInfo profile : userManager.getProfiles(user.getIdentifier())) {
+            final Context profileContext = getContextForUser(mContext, profile.getUserHandle());
+            if (profileContext == null) {
+                Slog.w(TAG, "Unable to create context for profile " + profile.id + " of user "
+                        + user.getIdentifier());
+                continue;
+            }
+            mTrackers.put(profile.id, new CalendarTracker(mContext, profileContext));
+        }
+        evaluateSubscriptions();
+    }
+
+    @Deprecated // Remove when inlining MODES_HSUM
     private void reloadTrackers() {
         if (DEBUG) Slog.d(TAG, "reloadTrackers");
+        if (android.app.Flags.modesHsum()) {
+            Slog.wtf(TAG, "Shouldn't call reloadTrackers() without user in MODES_HSUM",
+                    new Exception());
+        }
         for (int i = 0; i < mTrackers.size(); i++) {
             mTrackers.valueAt(i).setCallback(null);
         }
@@ -325,4 +380,9 @@
             evaluateSubscriptionsW();
         }
     };
+
+    @VisibleForTesting // (otherwise = NONE)
+    public SparseArray<CalendarTracker> getTrackers() {
+        return mTrackers;
+    }
 }
diff --git a/core/java/com/android/server/backup/NotificationBackupHelper.java b/services/core/java/com/android/server/notification/NotificationBackupHelper.java
similarity index 67%
rename from core/java/com/android/server/backup/NotificationBackupHelper.java
rename to services/core/java/com/android/server/notification/NotificationBackupHelper.java
index faa0509..ee9ec15 100644
--- a/core/java/com/android/server/backup/NotificationBackupHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationBackupHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.backup;
+package com.android.server.notification;
 
 import android.app.INotificationManager;
 import android.app.backup.BlobBackupHelper;
@@ -22,6 +22,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
+
 public class NotificationBackupHelper extends BlobBackupHelper {
     static final String TAG = "NotifBackupHelper";   // must be < 23 chars
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -34,9 +36,13 @@
 
     private final int mUserId;
 
+    private final NotificationManagerInternal mNm;
+
     public NotificationBackupHelper(int userId) {
         super(BLOB_VERSION, KEY_NOTIFICATIONS);
         mUserId = userId;
+
+        mNm = LocalServices.getService(NotificationManagerInternal.class);
     }
 
     @Override
@@ -44,9 +50,13 @@
         byte[] newPayload = null;
         if (KEY_NOTIFICATIONS.equals(key)) {
             try {
-                INotificationManager nm = INotificationManager.Stub.asInterface(
-                        ServiceManager.getService("notification"));
-                newPayload = nm.getBackupPayload(mUserId);
+                if (android.app.Flags.backupRestoreLogging()) {
+                    newPayload = mNm.getBackupPayload(mUserId, getLogger());
+                } else {
+                    INotificationManager nm = INotificationManager.Stub.asInterface(
+                            ServiceManager.getService("notification"));
+                    newPayload = nm.getBackupPayload(mUserId);
+                }
             } catch (Exception e) {
                 // Treat as no data
                 Slog.e(TAG, "Couldn't communicate with notification manager", e);
@@ -64,9 +74,13 @@
 
         if (KEY_NOTIFICATIONS.equals(key)) {
             try {
-                INotificationManager nm = INotificationManager.Stub.asInterface(
-                        ServiceManager.getService("notification"));
-                nm.applyRestore(payload, mUserId);
+                if (android.app.Flags.backupRestoreLogging()) {
+                    mNm.applyRestore(payload, mUserId, getLogger());
+                } else {
+                    INotificationManager nm = INotificationManager.Stub.asInterface(
+                            ServiceManager.getService("notification"));
+                    nm.applyRestore(payload, mUserId);
+                }
             } catch (Exception e) {
                 Slog.e(TAG, "Couldn't communicate with notification manager", e);
             }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 4b8de4e..d5d4070 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -19,6 +19,7 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
+import android.app.backup.BackupRestoreEventLogger;
 import android.service.notification.DeviceEffectsApplier;
 
 import java.util.Set;
@@ -43,7 +44,7 @@
 
     void onConversationRemoved(String pkg, int uid, Set<String> shortcuts);
 
-    /** Get the number of notification channels for a given package */
+    /** Get the number of app created notification channels for a given package */
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
 
     /** Does the specified package/uid have permission to post notifications? */
@@ -73,4 +74,9 @@
      * Otherwise an {@link IllegalStateException} will be thrown.
      */
     void setDeviceEffectsApplier(DeviceEffectsApplier applier);
+
+    // Backup/restore interface
+    byte[] getBackupPayload(int user, BackupRestoreEventLogger logger);
+
+    void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 88334eb..62d7622 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -216,6 +216,7 @@
 import android.app.UriGrantsManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.backup.BackupManager;
+import android.app.backup.BackupRestoreEventLogger;
 import android.app.compat.CompatChanges;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.role.RoleManager;
@@ -462,7 +463,7 @@
     static final int INVALID_UID = -1;
     static final String ROOT_PKG = "root";
 
-    static final String[] ALLOWED_ADJUSTMENTS = new String[] {
+    static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
             Adjustment.KEY_PEOPLE,
             Adjustment.KEY_SNOOZE_CRITERIA,
             Adjustment.KEY_USER_SENTIMENT,
@@ -1102,7 +1103,8 @@
         return false;
     }
 
-    void readPolicyXml(InputStream stream, boolean forRestore, int userId)
+    void readPolicyXml(InputStream stream, boolean forRestore, int userId,
+            BackupRestoreEventLogger logger)
             throws XmlPullParserException, NumberFormatException, IOException {
         final TypedXmlPullParser parser;
         if (forRestore) {
@@ -1189,7 +1191,7 @@
             InputStream infile = null;
             try {
                 infile = mPolicyFile.openRead();
-                readPolicyXml(infile, false /*forRestore*/, USER_ALL);
+                readPolicyXml(infile, false /*forRestore*/, USER_ALL, null);
 
                 // We re-load the default dnd packages to allow the newly added and denined.
                 final boolean isWatch = mPackageManagerClient.hasSystemFeature(
@@ -1239,7 +1241,7 @@
                 }
 
                 try {
-                    writePolicyXml(stream, false /*forBackup*/, USER_ALL);
+                    writePolicyXml(stream, false /*forBackup*/, USER_ALL, null);
                     mPolicyFile.finishWrite(stream);
                 } catch (IOException e) {
                     Slog.w(TAG, "Failed to save policy file, restoring backup", e);
@@ -1250,8 +1252,8 @@
         }
     }
 
-    private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
-            throws IOException {
+    private void writePolicyXml(OutputStream stream, boolean forBackup, int userId,
+            BackupRestoreEventLogger logger)  throws IOException {
         final TypedXmlSerializer out;
         if (forBackup) {
             out = Xml.newFastSerializer();
@@ -4119,6 +4121,24 @@
 
         @Override
         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+        public void allowAssistantAdjustment(String adjustmentType) {
+            checkCallerIsSystemOrSystemUiOrShell();
+            mAssistants.allowAdjustmentType(adjustmentType);
+
+            handleSavePolicyFile();
+        }
+
+        @Override
+        @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+        public void disallowAssistantAdjustment(String adjustmentType) {
+            checkCallerIsSystemOrSystemUiOrShell();
+            mAssistants.disallowAdjustmentType(adjustmentType);
+
+            handleSavePolicyFile();
+        }
+
+        @Override
+        @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
         public void setAdjustmentTypeSupportedState(INotificationListener token,
                 @Adjustment.Keys String key, boolean supported) {
             final long identity = Binder.clearCallingIdentity();
@@ -4133,6 +4153,7 @@
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
+            handleSavePolicyFile();
         }
 
         @Override
@@ -4371,8 +4392,9 @@
             List<NotificationChannel> channels = channelsList.getList();
             final int channelsSize = channels.size();
             ParceledListSlice<NotificationChannel> oldChannels =
-                    mPreferencesHelper.getNotificationChannels(pkg, uid, true);
-            final boolean hadChannel = oldChannels != null && !oldChannels.getList().isEmpty();
+                    mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
+            final boolean hadNonBundleChannel =
+                    oldChannels != null && !oldChannels.getList().isEmpty();
             boolean needsPolicyFileChange = false;
             boolean hasRequestedNotificationPermission = false;
             for (int i = 0; i < channelsSize; i++) {
@@ -4389,13 +4411,18 @@
                             mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
                                     false),
                             NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
-                    boolean hasChannel = hadChannel || hasRequestedNotificationPermission;
-                    if (!hasChannel) {
+                    boolean hasNonBundleChannel =
+                            hadNonBundleChannel || hasRequestedNotificationPermission;
+                    if (!hasNonBundleChannel) {
                         ParceledListSlice<NotificationChannel> currChannels =
-                                mPreferencesHelper.getNotificationChannels(pkg, uid, true);
-                        hasChannel = currChannels != null && !currChannels.getList().isEmpty();
+                                mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
+                        hasNonBundleChannel =
+                                currChannels != null && !currChannels.getList().isEmpty();
                     }
-                    if (!hadChannel && hasChannel && !hasRequestedNotificationPermission
+                    // show perm prompt if new non-bundle channel added and the user has not
+                    // seen the prompt
+                    if (!hadNonBundleChannel && hasNonBundleChannel
+                            && !hasRequestedNotificationPermission
                             && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
                         hasRequestedNotificationPermission = true;
                         if (mPermissionPolicyInternal == null) {
@@ -4630,7 +4657,7 @@
         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
                 int uid, boolean includeDeleted) {
             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
-            return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
+            return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted, true);
         }
 
         @Override
@@ -4762,7 +4789,7 @@
                     /* ignore */
                 }
                 return mPreferencesHelper.getNotificationChannels(
-                        targetPkg, targetUid, false /* includeDeleted */);
+                        targetPkg, targetUid, false /* includeDeleted */, true);
             }
             throw new SecurityException("Pkg " + callingPkg
                     + " cannot read channels for " + targetPkg + " in " + userId);
@@ -4891,7 +4918,7 @@
                     throw new SecurityException("Not currently an assistant");
             }
 
-            return mAssistants.getAllowedAssistantAdjustments();
+            return new ArrayList<>(mAssistants.getAllowedAssistantAdjustments());
         }
 
         /**
@@ -6171,7 +6198,7 @@
             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
             try {
-                writePolicyXml(baos, true /*forBackup*/, user);
+                writePolicyXml(baos, true /*forBackup*/, user, null);
                 return baos.toByteArray();
             } catch (IOException e) {
                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
@@ -6190,7 +6217,7 @@
             }
             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
             try {
-                readPolicyXml(bais, true /*forRestore*/, user);
+                readPolicyXml(bais, true /*forRestore*/, user, null);
                 handleSavePolicyFile();
             } catch (NumberFormatException | XmlPullParserException | IOException e) {
                 Slog.w(TAG, "applyRestore: error reading payload", e);
@@ -6631,7 +6658,7 @@
             verifyPrivilegedListener(token, user, true);
 
             return mPreferencesHelper.getNotificationChannels(pkg,
-                    getUidForPackageAndUser(pkg, user), false /* includeDeleted */);
+                    getUidForPackageAndUser(pkg, user), false /* includeDeleted */, true);
         }
 
         @Override
@@ -7392,6 +7419,37 @@
      */
     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
 
+        public byte[] getBackupPayload(int user, BackupRestoreEventLogger logger) {
+            checkCallerIsSystem();
+            if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            try {
+                writePolicyXml(baos, true /*forBackup*/, user, logger);
+                return baos.toByteArray();
+            } catch (IOException e) {
+                Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+            }
+            return null;
+        }
+
+        @Override
+        public void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger) {
+            checkCallerIsSystem();
+            if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
+                    + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
+            if (payload == null) {
+                Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
+                return;
+            }
+            final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+            try {
+                readPolicyXml(bais, true /*forRestore*/, user, logger);
+                handleSavePolicyFile();
+            } catch (NumberFormatException | XmlPullParserException | IOException e) {
+                Slog.w(TAG, "applyRestore: error reading payload", e);
+            }
+        }
+
         @Override
         public NotificationChannel getNotificationChannel(String pkg, int uid, String
                 channelId) {
@@ -7641,8 +7699,9 @@
     }
 
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
-        return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted).getList()
-                .size();
+        // don't show perm prompt if the only channels are bundle channels
+        return mPreferencesHelper.getNotificationChannels(
+                pkg, uid, includeDeleted, false).getList().size();
     }
 
     void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid,
@@ -7953,11 +8012,16 @@
     }
 
     /**
-     * Returns a channel, if exists, and restores deleted conversation channels.
+     * Returns a channel, if exists and is not a bundle channel, and restores deleted
+     * conversation channels.
      */
     @Nullable
     private NotificationChannel getNotificationChannelRestoreDeleted(String pkg,
             int callingUid, int notificationUid, String channelId, String conversationId) {
+        if (SYSTEM_RESERVED_IDS.contains(channelId)) {
+            // apps cannot post to these channels directly, in case they post incorrect content
+            return null;
+        }
         // Restore a deleted conversation channel, if exists. Otherwise use the parent channel.
         NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
                 pkg, notificationUid, channelId, conversationId,
@@ -11395,6 +11459,7 @@
         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
 
         private static final String ATT_TYPES = "types";
+        private static final String ATT_DENIED = "denied_adjustments";
         private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
 
         private final Object mLock = new Object();
@@ -11403,6 +11468,9 @@
         private Set<String> mAllowedAdjustments = new ArraySet<>();
 
         @GuardedBy("mLock")
+        private Set<String> mDeniedAdjustments = new ArraySet<>();
+
+        @GuardedBy("mLock")
         private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
 
         protected ComponentName mDefaultFromConfig = null;
@@ -11474,9 +11542,11 @@
                 IPackageManager pm) {
             super(context, lock, up, pm);
 
-            // Add all default allowed adjustment types.
-            for (int i = 0; i < ALLOWED_ADJUSTMENTS.length; i++) {
-                mAllowedAdjustments.add(ALLOWED_ADJUSTMENTS[i]);
+            if (!notificationClassification()) {
+                // Add all default allowed adjustment types.
+                for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
+                    mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
+                }
             }
         }
 
@@ -11539,17 +11609,28 @@
             return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
         }
 
-        protected List<String> getAllowedAssistantAdjustments() {
+        protected Set<String> getAllowedAssistantAdjustments() {
             synchronized (mLock) {
-                List<String> types = new ArrayList<>();
-                types.addAll(mAllowedAdjustments);
-                return types;
+                if (notificationClassification()) {
+                    Set<String> types = new HashSet<>(Set.of(DEFAULT_ALLOWED_ADJUSTMENTS));
+                    types.removeAll(mDeniedAdjustments);
+                    return types;
+                } else {
+                    Set<String> types = new HashSet<>();
+                    types.addAll(mAllowedAdjustments);
+                    return types;
+                }
             }
         }
 
         protected boolean isAdjustmentAllowed(String type) {
             synchronized (mLock) {
-                return mAllowedAdjustments.contains(type);
+                if (notificationClassification()) {
+                    return List.of(DEFAULT_ALLOWED_ADJUSTMENTS).contains(type)
+                            && !mDeniedAdjustments.contains(type);
+                } else {
+                    return mAllowedAdjustments.contains(type);
+                }
             }
         }
 
@@ -11911,6 +11992,30 @@
 
         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
         @GuardedBy("mNotificationLock")
+        public void allowAdjustmentType(@Adjustment.Keys String key) {
+            if (!android.service.notification.Flags.notificationClassification()) {
+                return;
+            }
+            mDeniedAdjustments.remove(key);
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                mHandler.post(() -> notifyCapabilitiesChanged(info));
+            }
+        }
+
+        @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+        @GuardedBy("mNotificationLock")
+        public void disallowAdjustmentType(@Adjustment.Keys String key) {
+            if (!android.service.notification.Flags.notificationClassification()) {
+                return;
+            }
+            mDeniedAdjustments.add(key);
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                mHandler.post(() -> notifyCapabilitiesChanged(info));
+            }
+        }
+
+        @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+        @GuardedBy("mNotificationLock")
         public void setAdjustmentTypeSupportedState(ManagedServiceInfo info,
                 @Adjustment.Keys String key, boolean supported) {
             if (!android.service.notification.Flags.notificationClassification()) {
@@ -11965,6 +12070,43 @@
                 }
             }
         }
+
+        @Override
+        protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
+            if (!android.service.notification.Flags.notificationClassification()) {
+                return;
+            }
+            synchronized (mLock) {
+                out.startTag(null, ATT_DENIED);
+                out.attribute(null, ATT_TYPES, TextUtils.join(",", mDeniedAdjustments));
+                out.endTag(null, ATT_DENIED);
+            }
+        }
+
+        @Override
+        protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
+            if (!android.service.notification.Flags.notificationClassification()) {
+                return;
+            }
+            if (ATT_DENIED.equals(tag)) {
+                final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+                synchronized (mLock) {
+                    mDeniedAdjustments.clear();
+                    if (!TextUtils.isEmpty(types)) {
+                        mDeniedAdjustments.addAll(Arrays.asList(types.split(",")));
+                    }
+                }
+            }
+        }
+
+        private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
+            final INotificationListener assistant = (INotificationListener) info.service;
+            try {
+                assistant.onAllowedAdjustmentsChanged();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 3ba9384..93f512b 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -334,7 +334,7 @@
             return helper.createWaveformVibration(vibrationPattern, insistent);
         }
 
-        if (com.android.server.notification.Flags.notificationVibrationInSoundUri()) {
+        if (com.android.server.notification.Flags.notificationVibrationInSoundUriForChannel()) {
             final VibrationEffect vibrationEffectFromSoundUri =
                     helper.createVibrationEffectFromSoundUri(channel.getSound());
             if (vibrationEffectFromSoundUri != null) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 3349b13..c9edc410 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1870,7 +1870,7 @@
 
     @Override
     public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
-            boolean includeDeleted) {
+            boolean includeDeleted, boolean includeBundles) {
         Objects.requireNonNull(pkg);
         List<NotificationChannel> channels = new ArrayList<>();
         synchronized (mLock) {
@@ -1882,7 +1882,9 @@
             for (int i = 0; i < N; i++) {
                 final NotificationChannel nc = r.channels.valueAt(i);
                 if (includeDeleted || !nc.isDeleted()) {
-                    channels.add(nc);
+                    if (includeBundles || !SYSTEM_RESERVED_IDS.contains(nc.getId())) {
+                        channels.add(nc);
+                    }
                 }
             }
             return new ParceledListSlice<>(channels);
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 8df24c9..001e91c 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -55,5 +55,5 @@
     void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
     void permanentlyDeleteNotificationChannels(String pkg, int uid);
     ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
-            boolean includeDeleted);
+            boolean includeDeleted, boolean includeBundles);
 }
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 6efe88f..24b090c 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -25,6 +25,7 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.Condition;
 import android.service.notification.ScheduleCalendar;
@@ -115,6 +116,11 @@
     }
 
     @Override
+    public void onUserSwitched(UserHandle user) {
+        // Nothing to do because time-based schedules are not tied to any user data.
+    }
+
+    @Override
     public void onDestroy() {
         super.onDestroy();
         if (DEBUG) Slog.d(TAG, "onDestroy");
diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
index 97073b7..656f9df 100644
--- a/services/core/java/com/android/server/notification/SystemConditionProviderService.java
+++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.service.notification.ConditionProviderService;
 import android.service.notification.IConditionProvider;
 import android.util.TimeUtils;
@@ -30,9 +31,10 @@
 
 public abstract class SystemConditionProviderService extends ConditionProviderService {
 
-    abstract public void dump(PrintWriter pw, DumpFilter filter);
-    abstract public boolean isValidConditionId(Uri id);
-    abstract public void onBootComplete();
+    public abstract void dump(PrintWriter pw, DumpFilter filter);
+    public abstract boolean isValidConditionId(Uri id);
+    public abstract void onBootComplete();
+    public abstract void onUserSwitched(UserHandle user);
 
     final ComponentName getComponent() {
         return new ComponentName("android", this.getClass().getName());
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 50bfbc3..b1f010c 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -102,16 +102,6 @@
     }
 
     @Override
-    public void onBootComplete() {
-        // noop
-    }
-
-    @Override
-    public void onUserSwitched() {
-        // noop
-    }
-
-    @Override
     public void onServiceAdded(ComponentName component) {
         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
         final int callingUid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/pinner/PinnerService.java b/services/core/java/com/android/server/pinner/PinnerService.java
index d7ac520..2c75926 100644
--- a/services/core/java/com/android/server/pinner/PinnerService.java
+++ b/services/core/java/com/android/server/pinner/PinnerService.java
@@ -121,9 +121,6 @@
     private static boolean PROP_PIN_PINLIST =
             SystemProperties.getBoolean("pinner.use_pinlist", true);
 
-    private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app.
-    private static final int MAX_ASSISTANT_PIN_SIZE = 60 * (1 << 20); // 60MB max for assistant app.
-
     public static final String ANON_REGION_STAT_NAME = "[anon]";
 
     private static final String SYSTEM_GROUP_NAME = "system";
@@ -179,8 +176,10 @@
 
     // Resource-configured pinner flags;
     private final boolean mConfiguredToPinCamera;
+    private final int mConfiguredCameraPinBytes;
     private final int mConfiguredHomePinBytes;
     private final boolean mConfiguredToPinAssistant;
+    private final int mConfiguredAssistantPinBytes;
     private final int mConfiguredWebviewPinBytes;
 
     // This is the percentage of total device memory that will be used to set the global quota.
@@ -250,6 +249,10 @@
         mDeviceConfigInterface = mInjector.getDeviceConfigInterface();
         mConfiguredToPinCamera = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerCameraApp);
+        mConfiguredCameraPinBytes = context.getResources().getInteger(
+                com.android.internal.R.integer.config_pinnerCameraPinBytes);
+        mConfiguredAssistantPinBytes = context.getResources().getInteger(
+                com.android.internal.R.integer.config_pinnerAssistantPinBytes);
         mConfiguredHomePinBytes = context.getResources().getInteger(
                 com.android.internal.R.integer.config_pinnerHomePinBytes);
         mConfiguredToPinAssistant = context.getResources().getBoolean(
@@ -812,11 +815,11 @@
     private int getSizeLimitForKey(@AppKey int key) {
         switch (key) {
             case KEY_CAMERA:
-                return MAX_CAMERA_PIN_SIZE;
+                return mConfiguredCameraPinBytes;
             case KEY_HOME:
                 return mConfiguredHomePinBytes;
             case KEY_ASSISTANT:
-                return MAX_ASSISTANT_PIN_SIZE;
+                return mConfiguredAssistantPinBytes;
             default:
                 return 0;
         }
@@ -1303,6 +1306,10 @@
             pw.format("   Maximum Pinner quota: %d bytes (%.2f MB)\n", mConfiguredMaxPinnedMemory,
                     mConfiguredMaxPinnedMemory / bytesPerMB);
             pw.format("   Max Home App Pin Bytes (without deps): %d\n", mConfiguredHomePinBytes);
+            pw.format("   Max Assistant App Pin Bytes (without deps): %d\n",
+                    mConfiguredAssistantPinBytes);
+            pw.format(
+                    "   Max Camera App Pin Bytes (without deps): %d\n", mConfiguredCameraPinBytes);
             pw.format("\nPinned Files:\n");
             synchronized (PinnerService.this) {
                 long totalSize = 0;
diff --git a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
index 49a6ffd..a221152 100644
--- a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
+++ b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
@@ -55,6 +55,8 @@
     private static final String ACTION_SWITCH_USER = "com.android.server.ACTION_SWITCH_TO_USER";
     private static final String ACTION_DISMISS_NOTIFICATION =
             "com.android.server.ACTION_DISMISS_NOTIFICATION";
+    private static final String EXTRA_NOTIFICATION_CLIENT_UID =
+            "com.android.server.EXTRA_CLIENT_UID";
     /**
      * The clientUid from the AudioFocusInfo of the background user,
      * for which an active notification is currently displayed.
@@ -101,7 +103,7 @@
         ActivityManager am = mSystemUserContext.getSystemService(ActivityManager.class);
 
         registerReceiver(am);
-        mBgUserListener = new BackgroundUserListener(mSystemUserContext);
+        mBgUserListener = new BackgroundUserListener();
         AudioPolicy.Builder focusControlPolicyBuilder = new AudioPolicy.Builder(mSystemUserContext);
         focusControlPolicyBuilder.setLooper(Looper.getMainLooper());
 
@@ -119,26 +121,16 @@
 
     final class BackgroundUserListener extends AudioPolicy.AudioPolicyFocusListener {
 
-        Context mSystemContext;
-
-        BackgroundUserListener(Context systemContext) {
-            mSystemContext = systemContext;
-        }
-
-        @SuppressLint("MissingPermission")
         public void onAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
             try {
-                BackgroundUserSoundNotifier.this.notifyForegroundUserAboutSoundIfNecessary(afi,
-                        mSystemContext.createContextAsUser(
-                                UserHandle.of(ActivityManager.getCurrentUser()), 0));
+                BackgroundUserSoundNotifier.this.notifyForegroundUserAboutSoundIfNecessary(afi);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
         }
 
-        @SuppressLint("MissingPermission")
         public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {
-            BackgroundUserSoundNotifier.this.dismissNotificationIfNecessary();
+            BackgroundUserSoundNotifier.this.dismissNotificationIfNecessary(afi.getClientUid());
         }
     }
 
@@ -160,7 +152,7 @@
                 if (mNotificationClientUid == -1) {
                     return;
                 }
-                dismissNotification();
+                dismissNotification(mNotificationClientUid);
 
                 if (DEBUG) {
                     final int actionIndex = intent.getAction().lastIndexOf(".") + 1;
@@ -171,7 +163,7 @@
                 }
 
                 if (ACTION_MUTE_SOUND.equals(intent.getAction())) {
-                    muteAlarmSounds(mSystemUserContext);
+                    muteAlarmSounds(mNotificationClientUid);
                 } else if (ACTION_SWITCH_USER.equals(intent.getAction())) {
                     activityManager.switchUser(UserHandle.getUserId(mNotificationClientUid));
                 }
@@ -193,17 +185,17 @@
      */
     @SuppressLint("MissingPermission")
     @VisibleForTesting
-    void muteAlarmSounds(Context context) {
-        AudioManager audioManager = context.getSystemService(AudioManager.class);
+    void muteAlarmSounds(int notificationClientUid) {
+        AudioManager audioManager = mSystemUserContext.getSystemService(AudioManager.class);
         if (audioManager != null) {
             for (AudioPlaybackConfiguration apc : audioManager.getActivePlaybackConfigurations()) {
-                if (apc.getClientUid() == mNotificationClientUid && apc.getPlayerProxy() != null) {
+                if (apc.getClientUid() == notificationClientUid && apc.getPlayerProxy() != null) {
                     apc.getPlayerProxy().stop();
                 }
             }
         }
 
-        AudioFocusInfo currentAfi = getAudioFocusInfoForNotification();
+        AudioFocusInfo currentAfi = getAudioFocusInfoForNotification(notificationClientUid);
         if (currentAfi != null) {
             mFocusControlAudioPolicy.sendFocusLossAndUpdate(currentAfi);
         }
@@ -212,9 +204,14 @@
     /**
      * Check if sound is coming from background user and show notification is required.
      */
+    @SuppressLint("MissingPermission")
     @VisibleForTesting
-    void notifyForegroundUserAboutSoundIfNecessary(AudioFocusInfo afi, Context foregroundContext)
-            throws RemoteException {
+    void notifyForegroundUserAboutSoundIfNecessary(AudioFocusInfo afi) throws RemoteException {
+        if (afi == null) {
+            return;
+        }
+        Context foregroundContext = mSystemUserContext.createContextAsUser(
+                UserHandle.of(ActivityManager.getCurrentUser()), 0);
         final int userId = UserHandle.getUserId(afi.getClientUid());
         final int usage = afi.getAttributes().getUsage();
         UserInfo userInfo = mUserManager.getUserInfo(userId);
@@ -232,8 +229,8 @@
 
                 mNotificationClientUid = afi.getClientUid();
 
-                mNotificationManager.notifyAsUser(LOG_TAG, mNotificationClientUid,
-                        createNotification(userInfo.name, foregroundContext),
+                mNotificationManager.notifyAsUser(LOG_TAG, afi.getClientUid(),
+                        createNotification(userInfo.name, foregroundContext, afi.getClientUid()),
                         foregroundContext.getUser());
             }
         }
@@ -245,14 +242,15 @@
      * focus ownership.
      */
     @VisibleForTesting
-    void dismissNotificationIfNecessary() {
-        if (getAudioFocusInfoForNotification() == null && mNotificationClientUid >= 0) {
+    void dismissNotificationIfNecessary(int notificationClientUid) {
+        if (getAudioFocusInfoForNotification(notificationClientUid) == null
+                && mNotificationClientUid >= 0) {
             if (DEBUG) {
                 Log.d(LOG_TAG, "Alarm ringing on background user "
-                        + UserHandle.getUserHandleForUid(mNotificationClientUid).getIdentifier()
+                        + UserHandle.getUserHandleForUid(notificationClientUid).getIdentifier()
                         + " left focus stack, dismissing notification");
             }
-            dismissNotification();
+            dismissNotification(notificationClientUid);
             mNotificationClientUid = -1;
         }
     }
@@ -262,8 +260,8 @@
      * shown.
      */
     @SuppressLint("MissingPermission")
-    private void dismissNotification() {
-        mNotificationManager.cancelAsUser(LOG_TAG, mNotificationClientUid, UserHandle.ALL);
+    private void dismissNotification(int notificationClientUid) {
+        mNotificationManager.cancelAsUser(LOG_TAG, notificationClientUid, UserHandle.ALL);
     }
 
     /**
@@ -272,11 +270,11 @@
     @SuppressLint("MissingPermission")
     @VisibleForTesting
     @Nullable
-    AudioFocusInfo getAudioFocusInfoForNotification() {
-        if (mNotificationClientUid >= 0) {
+    AudioFocusInfo getAudioFocusInfoForNotification(int notificationClientUid) {
+        if (notificationClientUid >= 0) {
             List<AudioFocusInfo> stack = mFocusControlAudioPolicy.getFocusStack();
             for (int i = stack.size() - 1; i >= 0; i--) {
-                if (stack.get(i).getClientUid() == mNotificationClientUid) {
+                if (stack.get(i).getClientUid() == notificationClientUid) {
                     return stack.get(i);
                 }
             }
@@ -284,22 +282,24 @@
         return null;
     }
 
-    private PendingIntent createPendingIntent(String intentAction) {
+    private PendingIntent createPendingIntent(String intentAction, int notificationClientUid) {
         final Intent intent = new Intent(intentAction);
-        PendingIntent resultPI =  PendingIntent.getBroadcast(mSystemUserContext, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-        return resultPI;
+        intent.putExtra(EXTRA_NOTIFICATION_CLIENT_UID, notificationClientUid);
+        return PendingIntent.getBroadcast(mSystemUserContext, notificationClientUid, intent,
+                PendingIntent.FLAG_IMMUTABLE);
     }
 
+    @SuppressLint("MissingPermission")
     @VisibleForTesting
-    Notification createNotification(String userName, Context fgContext) {
+    Notification createNotification(String userName, Context fgContext, int notificationClientUid) {
         final String title = fgContext.getString(R.string.bg_user_sound_notification_title_alarm,
                 userName);
         final int icon = R.drawable.ic_audio_alarm;
 
-        PendingIntent mutePI = createPendingIntent(ACTION_MUTE_SOUND);
-        PendingIntent switchPI = createPendingIntent(ACTION_SWITCH_USER);
-        PendingIntent dismissNotificationPI = createPendingIntent(ACTION_DISMISS_NOTIFICATION);
+        PendingIntent mutePI = createPendingIntent(ACTION_MUTE_SOUND, notificationClientUid);
+        PendingIntent switchPI = createPendingIntent(ACTION_SWITCH_USER, notificationClientUid);
+        PendingIntent dismissNotificationPI = createPendingIntent(ACTION_DISMISS_NOTIFICATION,
+                notificationClientUid);
 
         final Notification.Action mute = new Notification.Action.Builder(null,
                 fgContext.getString(R.string.bg_user_sound_notification_button_mute),
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 02afdd6..9e8598a 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -89,6 +89,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -893,7 +894,8 @@
 
         @Override
         public void onApexStaged(@NonNull ApexStagedEvent event) {
-            mArtManager.onApexStaged(event.stagedApexModuleNames);
+            mArtManager.onApexStaged(Arrays.stream(event.stagedApexInfos)
+                    .map(info -> info.moduleName).toArray(String[]::new));
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerNative.java b/services/core/java/com/android/server/pm/PackageManagerNative.java
index 66ecd6e..7d8573e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerNative.java
+++ b/services/core/java/com/android/server/pm/PackageManagerNative.java
@@ -20,7 +20,6 @@
 
 import static com.android.server.pm.PackageManagerService.TAG;
 
-import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManagerNative;
 import android.content.pm.IStagedApexObserver;
@@ -184,14 +183,8 @@
     }
 
     @Override
-    public String[] getStagedApexModuleNames() {
-        return mPm.mInstallerService.getStagingManager()
-                .getStagedApexModuleNames().toArray(new String[0]);
-    }
-
-    @Override
-    @Nullable
-    public StagedApexInfo getStagedApexInfo(String moduleName) {
-        return mPm.mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
+    public StagedApexInfo[] getStagedApexInfos() {
+        return mPm.mInstallerService.getStagingManager().getStagedApexInfos().toArray(
+                new StagedApexInfo[0]);
     }
 }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 94bdfbd..38cf0b9 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,7 +17,6 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.apex.ApexInfo;
 import android.apex.ApexSessionInfo;
 import android.apex.ApexSessionParams;
@@ -38,7 +37,6 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.Slog;
@@ -65,9 +63,9 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -807,14 +805,13 @@
     }
 
     /**
-     * Returns ApexInfo about APEX contained inside the session as a {@code Map<String, ApexInfo>},
-     * where the key of the map is the module name of the ApexInfo.
+     * Returns ApexInfo about APEX contained inside the session.
      *
-     * Returns an empty map if there is any error.
+     * Returns an empty list if there is any error.
      */
     @VisibleForTesting
     @NonNull
-    Map<String, ApexInfo> getStagedApexInfos(@NonNull StagedSession session) {
+    List<ApexInfo> getStagedApexInfos(@NonNull StagedSession session) {
         Preconditions.checkArgument(session != null, "Session is null");
         Preconditions.checkArgument(!session.hasParentSessionId(),
                 session.sessionId() + " session has parent session");
@@ -824,7 +821,7 @@
         // Even if caller calls this method on ready session, the session could be abandoned
         // right after this method is called.
         if (!session.isSessionReady() || session.isDestroyed()) {
-            return Collections.emptyMap();
+            return Collections.emptyList();
         }
 
         ApexSessionParams params = new ApexSessionParams();
@@ -838,20 +835,17 @@
             }
         }
         params.childSessionIds = childSessionIds.toArray();
-
-        ApexInfo[] infos = mApexManager.getStagedApexInfos(params);
-        Map<String, ApexInfo> result = new ArrayMap<>();
-        for (ApexInfo info : infos) {
-            result.put(info.moduleName, info);
-        }
-        return result;
+        return Arrays.asList(mApexManager.getStagedApexInfos(params));
     }
 
     /**
-     * Returns apex module names of all packages that are staged ready
+     * Returns ApexInfo list about APEXes contained inside all staged sessions.
+     *
+     * Returns an empty list if there is any error.
      */
-    List<String> getStagedApexModuleNames() {
-        List<String> result = new ArrayList<>();
+    @NonNull
+    List<StagedApexInfo> getStagedApexInfos() {
+        List<StagedApexInfo> result = new ArrayList<>();
         synchronized (mStagedSessions) {
             for (int i = 0; i < mStagedSessions.size(); i++) {
                 final StagedSession session = mStagedSessions.valueAt(i);
@@ -859,26 +853,7 @@
                         || session.hasParentSessionId() || !session.containsApexSession()) {
                     continue;
                 }
-                result.addAll(getStagedApexInfos(session).keySet());
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Returns ApexInfo of the {@code moduleInfo} provided if it is staged, otherwise returns null.
-     */
-    @Nullable
-    StagedApexInfo getStagedApexInfo(String moduleName) {
-        synchronized (mStagedSessions) {
-            for (int i = 0; i < mStagedSessions.size(); i++) {
-                final StagedSession session = mStagedSessions.valueAt(i);
-                if (!session.isSessionReady() || session.isDestroyed()
-                        || session.hasParentSessionId() || !session.containsApexSession()) {
-                    continue;
-                }
-                ApexInfo ai = getStagedApexInfos(session).get(moduleName);
-                if (ai != null) {
+                getStagedApexInfos(session).stream().map(ai -> {
                     StagedApexInfo info = new StagedApexInfo();
                     info.moduleName = ai.moduleName;
                     info.diskImagePath = ai.modulePath;
@@ -886,17 +861,19 @@
                     info.versionName = ai.versionName;
                     info.hasClassPathJars = ai.hasClassPathJars;
                     return info;
-                }
+                }).forEach(result::add);
             }
         }
-        return null;
+        return result;
     }
 
     private void notifyStagedApexObservers() {
         synchronized (mStagedApexObservers) {
+            List<StagedApexInfo> stagedApexInfos = getStagedApexInfos();
+            ApexStagedEvent event = new ApexStagedEvent();
+            event.stagedApexInfos =
+                    stagedApexInfos.toArray(new StagedApexInfo[stagedApexInfos.size()]);
             for (IStagedApexObserver observer : mStagedApexObservers) {
-                ApexStagedEvent event = new ApexStagedEvent();
-                event.stagedApexModuleNames = getStagedApexModuleNames().toArray(new String[0]);
                 try {
                     observer.onApexStaged(event);
                 } catch (RemoteException re) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index eb62b56..8ba56c5 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -771,6 +771,10 @@
     public void onGroupRemoved(int groupId) {
         mInteractivityByGroupId.remove(groupId);
         mWakefulnessSessionObserver.removePowerGroup(groupId);
+        if (mFlags.isPerDisplayWakeByTouchEnabled()) {
+            resetDisplayInteractivities();
+            mInputManagerInternal.setDisplayInteractivities(mDisplayInteractivities);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index 5f704a0..6f1e15b 100644
--- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -29,7 +29,6 @@
 import android.net.ConnectivityManager;
 import android.net.IpSecTransformState;
 import android.net.Network;
-import android.net.vcn.Flags;
 import android.net.vcn.VcnManager;
 import android.os.Handler;
 import android.os.HandlerExecutor;
@@ -233,7 +232,7 @@
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static int getMaxSeqNumIncreasePerSecond(@Nullable PersistableBundleWrapper carrierConfig) {
         int maxSeqNumIncrease = MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED;
-        if (Flags.handleSeqNumLeap() && carrierConfig != null) {
+        if (carrierConfig != null) {
             maxSeqNumIncrease =
                     carrierConfig.getInt(
                             VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY,
@@ -287,10 +286,8 @@
         // with the new interval
         mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig);
 
-        if (Flags.handleSeqNumLeap()) {
-            mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig);
-            mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig);
-        }
+        mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig);
+        mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig);
 
         if (canStart() != isStarted()) {
             if (canStart()) {
@@ -438,13 +435,10 @@
                 onValidationResultReceivedInternal(true /* isFailed */);
             }
 
-            // In both "valid" or "unusual_seq_num_leap" cases, trigger network validation
-            if (Flags.validateNetworkOnIpsecLoss()) {
-                // Trigger re-validation of the underlying network; if it fails, the VCN will
-                // attempt to migrate away.
-                mConnectivityManager.reportNetworkConnectivity(
-                        getNetwork(), false /* hasConnectivity */);
-            }
+            // In both "invalid" and "unusual_seq_num_leap" cases, trigger network validation. If
+            // validation fails, the VCN will attempt to migrate away.
+            mConnectivityManager.reportNetworkConnectivity(
+                    getNetwork(), false /* hasConnectivity */);
         }
     }
 
@@ -474,8 +468,7 @@
             boolean isUnusualSeqNumLeap = false;
 
             // Handle sequence number leap
-            if (Flags.handleSeqNumLeap()
-                    && maxSeqNumIncreasePerSecond != MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) {
+            if (maxSeqNumIncreasePerSecond != MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) {
                 final long timeDiffMillis =
                         newState.getTimestampMillis() - oldState.getTimestampMillis();
                 final long maxSeqNumIncrease = timeDiffMillis * maxSeqNumIncreasePerSecond / 1000;
@@ -506,7 +499,7 @@
                             + " actualPktCntDiff: "
                             + actualPktCntDiff);
 
-            if (Flags.handleSeqNumLeap() && expectedPktCntDiff < MIN_VALID_EXPECTED_RX_PACKET_NUM) {
+            if (expectedPktCntDiff < MIN_VALID_EXPECTED_RX_PACKET_NUM) {
                 // The sample size is too small to ensure a reliable detection result
                 return PacketLossCalculationResult.invalid();
             }
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
index 78e06d4..c852fb4 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
@@ -25,7 +25,6 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.vcn.Flags;
 import android.net.vcn.VcnManager;
 import android.net.vcn.VcnUnderlyingNetworkTemplate;
 import android.os.Handler;
@@ -297,10 +296,8 @@
         updatePriorityClass(
                 underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig);
 
-        if (Flags.evaluateIpsecLossOnLpNcChange()) {
-            for (NetworkMetricMonitor monitor : mMetricMonitors) {
-                monitor.onLinkPropertiesOrCapabilitiesChanged();
-            }
+        for (NetworkMetricMonitor monitor : mMetricMonitors) {
+            monitor.onLinkPropertiesOrCapabilitiesChanged();
         }
     }
 
@@ -316,10 +313,8 @@
         updatePriorityClass(
                 underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig);
 
-        if (Flags.evaluateIpsecLossOnLpNcChange()) {
-            for (NetworkMetricMonitor monitor : mMetricMonitors) {
-                monitor.onLinkPropertiesOrCapabilitiesChanged();
-            }
+        for (NetworkMetricMonitor monitor : mMetricMonitors) {
+            monitor.onLinkPropertiesOrCapabilitiesChanged();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index a44eb48..460de01 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -285,9 +285,6 @@
 import android.app.servertransaction.TopResumedActivityChangeItem;
 import android.app.servertransaction.TransferSplashScreenViewStateItem;
 import android.app.usage.UsageEvents.Event;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
-import android.compat.annotation.Overridable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -467,11 +464,6 @@
     // finished destroying itself.
     private static final int DESTROY_TIMEOUT = 10 * 1000;
 
-    @ChangeId
-    @Overridable
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
-    static final long UNIVERSAL_RESIZABLE_BY_DEFAULT = 357141415;
-
     final ActivityTaskManagerService mAtmService;
     final ActivityCallerState mCallerState;
     @NonNull
@@ -3192,7 +3184,7 @@
                 && mDisplayContent != null && mDisplayContent.getConfiguration()
                     .smallestScreenWidthDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
                 && mDisplayContent.getIgnoreOrientationRequest()
-                && info.isChangeEnabled(UNIVERSAL_RESIZABLE_BY_DEFAULT);
+                && info.isChangeEnabled(ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT);
         if (!compatEnabled && !mWmService.mConstants.mIgnoreActivityOrientationRequest) {
             return false;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 87fa62a..5b5bb88 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -86,6 +86,7 @@
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg;
 
 import android.annotation.IntDef;
@@ -2786,10 +2787,22 @@
             }
         }
 
-        if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
-                && ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 || mSourceRecord == null)) {
-            // ignore the flag if there is no the sourceRecord or without new_task flag
-            mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT;
+        if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
+            final boolean hasNewTaskFlag = (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0;
+            if (!hasNewTaskFlag || mSourceRecord == null) {
+                // ignore the flag if there is no the sourceRecord or without new_task flag
+                Slog.w(TAG_WM, !hasNewTaskFlag
+                        ? "Launch adjacent ignored due to missing NEW_TASK"
+                        : "Launch adjacent ignored due to missing source activity");
+                mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT;
+            }
+            // Ensure that the source task or its parents has not disabled launch-adjacent
+            if (mSourceRecord != null && mSourceRecord.getTask() != null &&
+                    mSourceRecord.getTask().isLaunchAdjacentDisabled()) {
+                Slog.w(TAG_WM, "Launch adjacent blocked by source task or ancestor");
+                mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT;
+            }
+
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 3d6b64b..3560565 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -589,7 +589,7 @@
      * sensitive environment.
      */
     public abstract TaskSnapshot getTaskSnapshotBlocking(int taskId,
-            boolean isLowResolution);
+            boolean isLowResolution, @TaskSnapshot.ReferenceFlags int usage);
 
     /** Returns true if uid is considered foreground for activity start purposes. */
     public abstract boolean isUidForeground(int uid);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3dfc8f4..4db478a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3946,6 +3946,28 @@
         }
     }
 
+    private TaskSnapshot getTaskSnapshotInner(int taskId, boolean isLowResolution,
+            @TaskSnapshot.ReferenceFlags int usage) {
+        final Task task;
+        synchronized (mGlobalLock) {
+            task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
+            if (task == null) {
+                Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
+                return null;
+            }
+            // Try to load snapshot from cache first, and add reference if the snapshot is in cache.
+            final TaskSnapshot snapshot = mWindowManager.mTaskSnapshotController.getSnapshot(taskId,
+                    task.mUserId, false /* restoreFromDisk */, isLowResolution);
+            if (snapshot != null) {
+                snapshot.addReference(usage);
+                return snapshot;
+            }
+        }
+        // Don't call this while holding the lock as this operation might hit the disk.
+        return mWindowManager.mTaskSnapshotController.getSnapshot(taskId,
+                task.mUserId, true /* restoreFromDisk */, isLowResolution);
+    }
+
     @Override
     public TaskSnapshot getTaskSnapshot(int taskId, boolean isLowResolution) {
         mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
@@ -7274,8 +7296,9 @@
 
         @Override
         public TaskSnapshot getTaskSnapshotBlocking(
-                int taskId, boolean isLowResolution) {
-            return ActivityTaskManagerService.this.getTaskSnapshot(taskId, isLowResolution);
+                int taskId, boolean isLowResolution, @TaskSnapshot.ReferenceFlags int usage) {
+            return ActivityTaskManagerService.this.getTaskSnapshotInner(
+                    taskId, isLowResolution, usage);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 515f148..a380ba1 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -558,7 +558,7 @@
                     .append(mBalAllowedByPiCreatorWithHardening);
             sb.append("; resultIfPiCreatorAllowsBal: ").append(mResultForCaller);
             sb.append("; callerStartMode: ").append(balStartModeToString(
-                    mCheckedOptions.getPendingIntentBackgroundActivityStartMode()));
+                    mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode()));
             sb.append("; hasRealCaller: ").append(hasRealCaller());
             sb.append("; isCallForResult: ").append(mIsCallForResult);
             sb.append("; isPendingIntent: ").append(isPendingIntent());
@@ -585,7 +585,7 @@
                 sb.append("; balAllowedByPiSender: ").append(mBalAllowedByPiSender);
                 sb.append("; resultIfPiSenderAllowsBal: ").append(mResultForRealCaller);
                 sb.append("; realCallerStartMode: ").append(balStartModeToString(
-                        mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode()));
+                        mCheckedOptions.getPendingIntentBackgroundActivityStartMode()));
             }
             // features
             sb.append("; balImproveRealCallerVisibilityCheck: ")
@@ -792,7 +792,8 @@
             // Allowed before V by creator
             if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) {
                 Slog.wtf(TAG, "With Android 15 BAL hardening this activity start may be blocked"
-                        + " if the PI creator upgrades target_sdk to 35+! "
+                        + " if the PI creator upgrades target_sdk to 35+!"
+                        + " goo.gle/android-bal"
                         + " (missing opt in by PI creator)!" + state);
                 return allowBasedOnCaller(state);
             }
@@ -802,6 +803,7 @@
             if (state.mBalAllowedByPiSender.allowsBackgroundActivityStarts()) {
                 Slog.wtf(TAG, "With Android 14 BAL hardening this activity start will be blocked"
                         + " if the PI sender upgrades target_sdk to 34+! "
+                        + " goo.gle/android-bal"
                         + " (missing opt in by PI sender)!" + state);
                 return allowBasedOnRealCaller(state);
             }
@@ -829,7 +831,8 @@
     }
 
     private BalVerdict abortLaunch(BalState state) {
-        Slog.wtf(TAG, "Background activity launch blocked! " + state);
+        Slog.wtf(TAG, "Background activity launch blocked! goo.gle/android-bal "
+                + state);
         if (balShowToastsBlocked()
                 && (state.mResultForCaller.allows() || state.mResultForRealCaller.allows())) {
             // only show a toast if either caller or real caller could launch if they opted in
@@ -1044,6 +1047,24 @@
                     "realCallingUid has BAL permission.");
         }
 
+        // don't abort if the realCallingUid has SYSTEM_ALERT_WINDOW permission
+        Slog.i(TAG, "hasSystemAlertWindowPermission(" + state.mRealCallingUid + ", "
+                + state.mRealCallingPid + ", " + state.mRealCallingPackage + ") "
+                + balStartModeToString(
+                state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()));
+        if (state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
+                == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+                && mService.hasSystemAlertWindowPermission(state.mRealCallingUid,
+                state.mRealCallingPid, state.mRealCallingPackage)) {
+            Slog.w(
+                    TAG,
+                    "Background activity start for "
+                            + state.mRealCallingPackage
+                            + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
+            return new BalVerdict(BAL_ALLOW_SAW_PERMISSION,
+                    /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted");
+        }
+
         // if the realCallingUid is a persistent system process, abort if the IntentSender
         // wasn't allowed to start an activity
         if (state.mForcedBalByPiSender.allowsBackgroundActivityStarts()
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 3dc035e..cbe3d79 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -401,6 +401,7 @@
                 || !Objects.equals(first.deviceProductInfo, second.deviceProductInfo)
                 || first.modeId != second.modeId
                 || first.renderFrameRate != second.renderFrameRate
+                || first.hasArrSupport != second.hasArrSupport
                 || first.defaultModeId != second.defaultModeId
                 || first.userPreferredModeId != second.userPreferredModeId
                 || !Arrays.equals(first.supportedModes, second.supportedModes)
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 6a23aaa..e9c6e93 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -274,34 +274,7 @@
         if (caller != controlTarget) {
             if (Flags.refactorInsetsController()) {
                 if (isImeInputTarget(caller)) {
-                    // In case of the multi window mode, update the requestedVisibleTypes from
-                    // the controlTarget (=RemoteInsetsControlTarget) via DisplayImeController.
-                    // Then, trigger onRequestedVisibleTypesChanged for the controlTarget with
-                    // its new requested visibility for the IME
-                    boolean imeVisible = caller.isRequestedVisible(WindowInsets.Type.ime());
-                    if (controlTarget != null) {
-                        ImeTracker.forLogging().onProgress(statsToken,
-                                ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
-                        controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
-                    } else if (caller instanceof InsetsControlTarget) {
-                        // In case of a virtual display that cannot show the IME, the
-                        // controlTarget will be null here, as no controlTarget was set yet. In
-                        // that case, proceed similar to the multi window mode (fallback =
-                        // RemoteInsetsControlTarget of the default display)
-                        controlTarget = mDisplayContent.getImeHostOrFallback(
-                                ((InsetsControlTarget) caller).getWindow());
-
-                        if (controlTarget != caller) {
-                            ImeTracker.forLogging().onProgress(statsToken,
-                                    ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
-                            controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
-                        } else {
-                            ImeTracker.forLogging().onFailed(statsToken,
-                                    ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
-                        }
-                    }
-
-                    invokeOnImeRequestedChangedListener(caller, statsToken);
+                    reportImeInputTargetStateToControlTarget(caller, controlTarget, statsToken);
                 } else {
                     // TODO(b/353463205) add ImeTracker?
                 }
@@ -332,16 +305,44 @@
         if (Flags.refactorInsetsController() && target != null) {
             InsetsControlTarget imeControlTarget = getControlTarget();
             if (target != imeControlTarget) {
-                // If the targetWin is not the imeControlTarget (=RemoteInsetsControlTarget) let it
-                // know about the new requestedVisibleTypes for the IME.
-                if (imeControlTarget != null) {
-                    imeControlTarget.setImeInputTargetRequestedVisibility(
-                            (target.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
-                }
+                // TODO(b/353463205): start new request here?
+                reportImeInputTargetStateToControlTarget(target, imeControlTarget,
+                        null /* statsToken */);
             }
         }
     }
 
+    private void reportImeInputTargetStateToControlTarget(@NonNull InsetsTarget imeInsetsTarget,
+            InsetsControlTarget controlTarget, @Nullable ImeTracker.Token statsToken) {
+        // In case of the multi window mode, update the requestedVisibleTypes from
+        // the controlTarget (=RemoteInsetsControlTarget) via DisplayImeController.
+        // Then, trigger onRequestedVisibleTypesChanged for the controlTarget with
+        // its new requested visibility for the IME
+        boolean imeVisible = imeInsetsTarget.isRequestedVisible(WindowInsets.Type.ime());
+        if (controlTarget != null) {
+            ImeTracker.forLogging().onProgress(statsToken,
+                    ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
+            controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
+        } else if (imeInsetsTarget instanceof InsetsControlTarget) {
+            // In case of a virtual display that cannot show the IME, the
+            // controlTarget will be null here, as no controlTarget was set yet. In
+            // that case, proceed similar to the multi window mode (fallback =
+            // RemoteInsetsControlTarget of the default display)
+            controlTarget = mDisplayContent.getImeHostOrFallback(
+                    ((InsetsControlTarget) imeInsetsTarget).getWindow());
+
+            if (controlTarget != imeInsetsTarget) {
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
+                controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
+            } else {
+                ImeTracker.forLogging().onFailed(statsToken,
+                        ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
+            }
+        }
+        invokeOnImeRequestedChangedListener(imeInsetsTarget, statsToken);
+    }
+
     // TODO(b/353463205) check callers to see if we can make statsToken @NonNull
     private void invokeOnImeRequestedChangedListener(InsetsTarget insetsTarget,
             @Nullable ImeTracker.Token statsToken) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 98919d9..a4e4deb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -503,6 +503,11 @@
     boolean mIsTrimmableFromRecents;
 
     /**
+     * Sets whether the launch-adjacent flag is respected or not for this task or its child tasks.
+     */
+    private boolean mLaunchAdjacentDisabled;
+
+    /**
      * Bounds offset should be applied when calculating compatible configuration for apps targeting
      * SDK level 34 or before.
      */
@@ -3802,6 +3807,9 @@
         pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
         pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
         pw.print(prefix); pw.println(" isTrimmable=" + mIsTrimmableFromRecents);
+        if (mLaunchAdjacentDisabled) {
+            pw.println(prefix + "mLaunchAdjacentDisabled=true");
+        }
     }
 
     @Override
@@ -5734,6 +5742,12 @@
     }
 
     private boolean canMoveTaskToBack(Task task) {
+        // Checks whether a task is a child of this task because it can be reparetned when
+        // transition is deferred.
+        if (task != this && task.getParent() != this) {
+            return false;
+        }
+
         // In LockTask mode, moving a locked task to the back of the root task may expose unlocked
         // ones. Therefore we need to check if this operation is allowed.
         if (!mAtmService.getLockTaskController().canMoveTaskToBack(task)) {
@@ -5803,7 +5817,7 @@
                     (deferred) -> {
                         // Need to check again if deferred since the system might
                         // be in a different state.
-                        if (!isAttached() || (deferred && !canMoveTaskToBack(tr))) {
+                        if (!tr.isAttached() || (deferred && !canMoveTaskToBack(tr))) {
                             Slog.e(TAG, "Failed to move task to back after saying we could: "
                                     + tr.mTaskId);
                             transition.abort();
@@ -6268,6 +6282,28 @@
     }
 
     /**
+     * Sets this task and its children to disable respecting launch-adjacent.
+     */
+    void setLaunchAdjacentDisabled(boolean disabled) {
+        mLaunchAdjacentDisabled = disabled;
+    }
+
+    /**
+     * Returns whether this task or any of its ancestors have disabled respecting the
+     * launch-adjacent flag.
+     */
+    boolean isLaunchAdjacentDisabled() {
+        Task t = this;
+        while (t != null) {
+            if (t.mLaunchAdjacentDisabled) {
+                return true;
+            }
+            t = t.getParent().asTask();
+        }
+        return false;
+    }
+
+    /**
      * Return true if the activityInfo has the same requiredDisplayCategory as this task.
      */
     boolean isSameRequiredDisplayCategory(@NonNull ActivityInfo info) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 5dd3bbc..2c71c1a 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1074,6 +1074,8 @@
             final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
             // We only allow this for created by organizer tasks.
             if (launchRootTask != null && launchRootTask.mCreatedByOrganizer) {
+                Slog.i(TAG_WM, "Using launch root task from activity options: taskId="
+                        + launchRootTask.mTaskId);
                 return launchRootTask;
             }
         }
@@ -1081,19 +1083,25 @@
         // Use launch-adjacent-flag-root if launching with launch-adjacent flag.
         if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
                 && mLaunchAdjacentFlagRootTask != null) {
+            final Task launchAdjacentRootAdjacentTask =
+                    mLaunchAdjacentFlagRootTask.getAdjacentTask();
             if (sourceTask != null && (sourceTask == candidateTask
                     || sourceTask.topRunningActivity() == null)) {
                 // Do nothing when task that is getting opened is same as the source or when
                 // the source is no-longer valid.
                 Slog.w(TAG_WM, "Ignoring LAUNCH_ADJACENT because adjacent source is gone.");
             } else if (sourceTask != null
-                    && mLaunchAdjacentFlagRootTask.getAdjacentTask() != null
+                    && launchAdjacentRootAdjacentTask != null
                     && (sourceTask == mLaunchAdjacentFlagRootTask
                     || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) {
-                // If the adjacent launch is coming from the same root, launch to
-                // adjacent root instead.
-                return mLaunchAdjacentFlagRootTask.getAdjacentTask();
+                // If the adjacent launch is coming from the same root that was specified as the
+                // launch-adjacent task, so instead we launch to its adjacent root instead.
+                Slog.i(TAG_WM, "Using adjacent-to specified launch-adjacent task: taskId="
+                        + launchAdjacentRootAdjacentTask.mTaskId);
+                return launchAdjacentRootAdjacentTask;
             } else {
+                Slog.i(TAG_WM, "Using specified launch-adjacent task: taskId="
+                        + mLaunchAdjacentFlagRootTask.mTaskId);
                 return mLaunchAdjacentFlagRootTask;
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 82c7a93..166d74b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -69,6 +69,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
@@ -1450,6 +1451,17 @@
                 task.setTrimmableFromRecents(hop.isTrimmableFromRecents());
                 break;
             }
+            case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT: {
+                final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
+                final Task task = container != null ? container.asTask() : null;
+                if (task == null || !task.isAttached()) {
+                    Slog.e(TAG, "Attempt to operate on unknown or detached container: "
+                            + container);
+                    break;
+                }
+                task.setLaunchAdjacentDisabled(hop.isLaunchAdjacentDisabled());
+                break;
+            }
             case HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION: {
                 if (mService.mBackNavigationController.restoreBackNavigation()) {
                     effects |= TRANSACT_EFFECTS_LIFECYCLE;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7e450dd..aca6f72 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16815,6 +16815,9 @@
             }
         }
         EnforcingAdmin enforcingAdmin;
+
+        // TODO(b/370472975): enable when we stop policy enforecer callback from blocking the main
+        //  thread
         if (Flags.setPermissionGrantStateCoexistence()) {
             enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
                     admin,
@@ -16840,54 +16843,7 @@
                 callback.sendResult(null);
                 return;
             }
-        } else {
-            Preconditions.checkCallAuthorization((caller.hasAdminComponent()
-                    && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
-                    || isFinancedDeviceOwner(caller)))
-                    || (caller.hasPackage() && isCallerDelegate(caller,
-                    DELEGATION_PERMISSION_GRANT)));
-            if (SENSOR_PERMISSIONS.contains(permission)
-                    && grantState == PERMISSION_GRANT_STATE_GRANTED
-                    && !canAdminGrantSensorsPermissions()) {
-                if (mInjector.isChangeEnabled(THROW_SECURITY_EXCEPTION_FOR_SENSOR_PERMISSIONS,
-                        caller.getPackageName(), caller.getUserId())) {
-                    throw new SecurityException(
-                            "Caller not permitted to grant sensor permissions.");
-                } else {
-                    Slogf.e(LOG_TAG, "Caller attempted to grant sensor permissions but denied");
-                    // This is to match the legacy behaviour.
-                    callback.sendResult(Bundle.EMPTY);
-                    return;
-                }
-            }
-            synchronized (getLockObject()) {
-                long ident = mInjector.binderClearCallingIdentity();
-                try {
-                    boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
-                            >= android.os.Build.VERSION_CODES.Q;
-                    if (!isPostQAdmin) {
-                        // Legacy admins assume that they cannot control pre-M apps
-                        if (getTargetSdk(packageName, caller.getUserId())
-                                < android.os.Build.VERSION_CODES.M) {
-                            callback.sendResult(null);
-                            return;
-                        }
-                    }
-                    if (!isRuntimePermission(permission)) {
-                        callback.sendResult(null);
-                        return;
-                    }
-                } catch (SecurityException e) {
-                    Slogf.e(LOG_TAG, "Could not set permission grant state", e);
-                    callback.sendResult(null);
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(ident);
-                }
-            }
-        }
-        // TODO(b/278710449): enable when we stop policy enforecer callback from blocking the main
-        //  thread
-        if (false) {
+
             // TODO(b/266924257): decide how to handle the internal state if the package doesn't
             //  exist, or the permission isn't requested by the app, because we could end up with
             //  inconsistent state between the policy engine and package manager. Also a package
@@ -16913,11 +16869,43 @@
                 callback.sendResult(null);
             }
         } else {
+            Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+                    && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+                    || isFinancedDeviceOwner(caller)))
+                    || (caller.hasPackage() && isCallerDelegate(caller,
+                    DELEGATION_PERMISSION_GRANT)));
+            if (SENSOR_PERMISSIONS.contains(permission)
+                    && grantState == PERMISSION_GRANT_STATE_GRANTED
+                    && !canAdminGrantSensorsPermissions()) {
+                if (mInjector.isChangeEnabled(THROW_SECURITY_EXCEPTION_FOR_SENSOR_PERMISSIONS,
+                        caller.getPackageName(), caller.getUserId())) {
+                    throw new SecurityException(
+                            "Caller not permitted to grant sensor permissions.");
+                } else {
+                    Slogf.e(LOG_TAG, "Caller attempted to grant sensor permissions but denied");
+                    // This is to match the legacy behaviour.
+                    callback.sendResult(Bundle.EMPTY);
+                    return;
+                }
+            }
             synchronized (getLockObject()) {
                 long ident = mInjector.binderClearCallingIdentity();
+                boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
+                        >= android.os.Build.VERSION_CODES.Q;
+
                 try {
-                    boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
-                            >= android.os.Build.VERSION_CODES.Q;
+                    if (!isPostQAdmin) {
+                        // Legacy admins assume that they cannot control pre-M apps
+                        if (getTargetSdk(packageName, caller.getUserId())
+                                < android.os.Build.VERSION_CODES.M) {
+                            callback.sendResult(null);
+                            return;
+                        }
+                    }
+                    if (!isRuntimePermission(permission)) {
+                        callback.sendResult(null);
+                        return;
+                    }
                     if (grantState == PERMISSION_GRANT_STATE_GRANTED
                             || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
                             || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
@@ -16939,7 +16927,6 @@
                     }
                 } catch (SecurityException e) {
                     Slogf.e(LOG_TAG, "Could not set permission grant state", e);
-
                     callback.sendResult(null);
                 } finally {
                     mInjector.binderRestoreCallingIdentity(ident);
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index cc340c0..891c334 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -58,6 +58,7 @@
 import android.os.UserManager;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
@@ -1737,6 +1738,11 @@
         pw.decreaseIndent();
     }
 
+    @Override
+    protected void onUnhandledException(int code, int flags, Exception e) {
+        Slog.wtf(TAG, "Uncaught exception in AudioService: " + code + ", " + flags, e);
+    }
+
     @GuardedBy("mUsbMidiLock")
     private boolean isUsbMidiDeviceInUseLocked(MidiDeviceInfo info) {
         String name = info.getProperties().getString(MidiDeviceInfo.PROPERTY_NAME);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 01b2d3e..fdf6b80 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -2343,6 +2343,41 @@
         }
     }
 
+    @Test
+    public void stylusUsageStarted_disablesAutomaticBrightnessStrategy() {
+        when(mDisplayManagerFlagsMock.isBlockAutobrightnessChangesOnStylusUsage())
+                .thenReturn(true);
+        when(mDisplayManagerFlagsMock.isRefactorDisplayPowerControllerEnabled())
+                .thenReturn(true);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+        advanceTime(2);
+        clearInvocations(mHolder.automaticBrightnessController);
+        mHolder.dpc.stylusGestureStarted(2000000);
+
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+        verify(mHolder.automaticBrightnessController, times(0))
+                .getAutomaticScreenBrightness(any());
+
+        // Stylus usage timed out, hence autobrightness is now enabled back again
+        advanceTime(6);
+        verify(mHolder.automaticBrightnessController).getAutomaticScreenBrightness(null);
+
+        // Ideally we should be able to assert against new BrightnessEvent(Display.DEFAULT_DISPLAY),
+        // but because brightnessEvent has the mTime field which refers to the current time,
+        // asserting against that is non-trivial
+        verify(mHolder.automaticBrightnessController).getAutomaticScreenBrightness(
+                any(BrightnessEvent.class));
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -2406,6 +2441,7 @@
                 .thenReturn(new int[0]);
         when(displayDeviceConfigMock.getDefaultDozeBrightness())
                 .thenReturn(DEFAULT_DOZE_BRIGHTNESS);
+        when(displayDeviceConfigMock.getIdleStylusTimeoutMillis()).thenReturn(5);
 
         when(displayDeviceConfigMock.getBrightnessRampFastDecrease())
                 .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_DECREASE);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index d831cf8..b6da3ae 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -51,6 +51,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -209,8 +210,8 @@
         when(mResourcesMock.getIntArray(
                 com.android.internal.R.array.config_deviceStatesOnWhichToSleep))
                 .thenReturn(new int[]{0});
-        when(mSyntheticModeManagerMock.createAppSupportedModes(any(), any())).thenAnswer(
-                AdditionalAnswers.returnsSecondArg());
+        when(mSyntheticModeManagerMock.createAppSupportedModes(any(), any(), anyBoolean()))
+                .thenAnswer(AdditionalAnswers.returnsSecondArg());
 
         when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(false);
         mLooper = new TestLooper();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 8936f06..b002a1f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
@@ -87,7 +88,7 @@
         mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
                 DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 60)};
         when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(mDisplayDeviceInfo);
-        when(mSyntheticModeManager.createAppSupportedModes(any(), any())).thenAnswer(
+        when(mSyntheticModeManager.createAppSupportedModes(any(), any(), anyBoolean())).thenAnswer(
                 AdditionalAnswers.returnsSecondArg());
 
         // Disable binder caches in this process.
@@ -582,7 +583,8 @@
         Display.Mode[] appSupportedModes = new Display.Mode[] {new Display.Mode(OTHER_MODE_ID,
                 DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 45)};
         when(mSyntheticModeManager.createAppSupportedModes(
-                any(), eq(mDisplayDeviceInfo.supportedModes))).thenReturn(appSupportedModes);
+                any(), eq(mDisplayDeviceInfo.supportedModes), anyBoolean()))
+                .thenReturn(appSupportedModes);
 
         mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
         DisplayInfo info = mLogicalDisplay.getDisplayInfoLocked();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessReasonTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessReasonTest.java
index 04b79b4..d93ee84 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessReasonTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessReasonTest.java
@@ -74,7 +74,7 @@
 
     @Test
     public void setModifierDoesntSetIfModifierIsBeyondExtremes() {
-        int extremeModifier = 0x40; // equal to BrightnessReason.MODIFIER_MASK * 2
+        int extremeModifier = 0x80;
 
         // reset modifier
         mBrightnessReason.setModifier(0);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index c069875..b3baa5d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -125,7 +125,7 @@
                 DisplayManagerInternal.DisplayOffloadSession.class));
         verify(displayBrightnessStrategy).updateBrightness(
                 eq(new StrategyExecutionRequest(displayPowerRequest, DEFAULT_BRIGHTNESS,
-                        /* userSetBrightnessChanged= */ false)));
+                        /* userSetBrightnessChanged= */ false, /* isStylusBeingUsed */ false)));
         assertEquals(mDisplayBrightnessController.getCurrentDisplayBrightnessStrategy(),
                 displayBrightnessStrategy);
     }
@@ -559,4 +559,11 @@
                 displayDeviceConfig, handler, brightnessMappingStrategy, isDisplayEnabled,
                 leadDisplayId);
     }
+
+    @Test
+    public void setStylusBeingUsed_setsStylusInUseState() {
+        assertFalse(mDisplayBrightnessController.isStylusBeingUsed());
+        mDisplayBrightnessController.setStylusBeingUsed(true);
+        assertTrue(mDisplayBrightnessController.isStylusBeingUsed());
+    }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index a44c517..fe15051 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -68,6 +68,8 @@
 @RunWith(AndroidJUnit4.class)
 public final class DisplayBrightnessStrategySelectorTest {
     private static final boolean DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING = false;
+    private static final boolean STYLUS_IS_NOT_BEING_USED = false;
+    private static final boolean STYLUS_IS_BEING_USED = true;
     private static final int DISPLAY_ID = 1;
 
     @Mock
@@ -196,7 +198,8 @@
                 DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mDozeBrightnessModeStrategy);
     }
 
@@ -212,7 +215,8 @@
                 DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
         assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mDozeBrightnessModeStrategy);
     }
 
@@ -226,7 +230,8 @@
                 DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
         assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mDozeBrightnessModeStrategy);
     }
 
@@ -249,7 +254,8 @@
 
         assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mDozeBrightnessModeStrategy);
     }
 
@@ -259,7 +265,8 @@
                 DisplayManagerInternal.DisplayPowerRequest.class);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_OFF,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mScreenOffBrightnessModeStrategy);
     }
 
@@ -271,7 +278,8 @@
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mOverrideBrightnessStrategy);
     }
 
@@ -284,7 +292,8 @@
         when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(0.3f);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mTemporaryBrightnessStrategy);
     }
 
@@ -298,7 +307,8 @@
         when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mBoostBrightnessStrategy);
     }
 
@@ -312,7 +322,8 @@
         when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mInvalidBrightnessStrategy);
     }
 
@@ -323,7 +334,8 @@
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(0.3f);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mFollowerBrightnessStrategy);
     }
 
@@ -341,7 +353,8 @@
         when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(0.3f);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mOffloadBrightnessStrategy);
     }
 
@@ -365,7 +378,8 @@
         when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(true);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mAutomaticBrightnessStrategy);
         verify(mAutomaticBrightnessStrategy).setAutoBrightnessState(Display.STATE_ON,
                 true, BrightnessReason.REASON_UNKNOWN,
@@ -373,6 +387,32 @@
                 /* useNormalBrightnessForDoze= */ false, 0.1f, false);
     }
 
+
+    @Test
+    public void selectStrategy_doesNotSelectAutomaticStrategyWhenStylusInUse() {
+        when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+        when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
+        when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
+        when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
+        when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
+                true);
+        mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
+                mInjector, DISPLAY_ID, mDisplayManagerFlags);
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
+        when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
+        when(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()).thenReturn(true);
+        when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(true);
+        assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy(
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_BEING_USED)),
+                mAutomaticBrightnessStrategy);
+    }
+
     @Test
     public void selectStrategy_selectsAutomaticFallbackStrategyWhenValid() {
         when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
@@ -389,7 +429,8 @@
         when(mAutoBrightnessFallbackStrategy.isValid()).thenReturn(true);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mAutoBrightnessFallbackStrategy);
     }
 
@@ -407,7 +448,8 @@
         assertNotEquals(mOffloadBrightnessStrategy,
                 mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)));
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)));
     }
 
     @Test
@@ -425,7 +467,8 @@
         when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(false);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
                         new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                                0.1f, false, mDisplayOffloadSession)),
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED)),
                 mFallbackBrightnessStrategy);
     }
 
@@ -440,7 +483,8 @@
 
         mDisplayBrightnessStrategySelector.selectStrategy(
                 new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
-                        0.1f, false, mDisplayOffloadSession));
+                        0.1f, false, mDisplayOffloadSession,
+                        STYLUS_IS_NOT_BEING_USED));
 
         StrategySelectionNotifyRequest strategySelectionNotifyRequest =
                 new StrategySelectionNotifyRequest(displayPowerRequest, Display.STATE_ON,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java
index 99dfa73..2a71af0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java
@@ -129,7 +129,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mAutoBrightnessFallbackStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index efa8b3e..8a1f860 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -637,7 +637,7 @@
                 .build();
         DisplayBrightnessState actualDisplayBrightnessState = mAutomaticBrightnessStrategy
                 .updateBrightness(new StrategyExecutionRequest(displayPowerRequest, 0.6f,
-                        /* userSetBrightnessChanged= */ true));
+                        /* userSetBrightnessChanged= */ true, /* isStylusBeingUsed */ false));
         assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
     }
 
@@ -686,7 +686,7 @@
                 .build();
         DisplayBrightnessState actualDisplayBrightnessState = mAutomaticBrightnessStrategy
                 .updateBrightness(new StrategyExecutionRequest(displayPowerRequest, 0.6f,
-                        /* userSetBrightnessChanged= */ true));
+                        /* userSetBrightnessChanged= */ true, /* isStylusBeingUsed */ false));
         assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
     }
 
@@ -725,7 +725,7 @@
                 .build();
         DisplayBrightnessState actualDisplayBrightnessState = mAutomaticBrightnessStrategy
                 .updateBrightness(new StrategyExecutionRequest(displayPowerRequest, 0.6f,
-                        /* userSetBrightnessChanged= */ true));
+                        /* userSetBrightnessChanged= */ true, /* isStylusBeingUsed */ false));
         assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
     }
 
@@ -764,7 +764,7 @@
                 .build();
         DisplayBrightnessState actualDisplayBrightnessState = mAutomaticBrightnessStrategy
                 .updateBrightness(new StrategyExecutionRequest(displayPowerRequest, 0.6f,
-                        /* userSetBrightnessChanged= */ true));
+                        /* userSetBrightnessChanged= */ true, /* isStylusBeingUsed */ false));
         assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
index 275bb3ef..c03309e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
@@ -60,7 +60,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mBoostBrightnessStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
index 23e447c..e7f80b0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
@@ -57,7 +57,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mDozeBrightnessModeStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
index c4a5790..dcfa174 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
@@ -61,7 +61,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mFallbackBrightnessStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, currentBrightness,
-                                /* userSetBrightnessChanged= */ true));
+                                /* userSetBrightnessChanged= */ true,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
index c01f96e..239cdb6 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
@@ -61,7 +61,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mFollowerBrightnessStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(expectedDisplayBrightnessState, updatedDisplayBrightnessState);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java
index 9fb2afa..77302f8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java
@@ -72,7 +72,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mOffloadBrightnessStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
         assertEquals(PowerManager.BRIGHTNESS_INVALID_FLOAT, mOffloadBrightnessStrategy
                 .getOffloadScreenBrightness(), 0.0f);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
index e8b4c06..cc21af1 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
@@ -60,7 +60,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mOverrideBrightnessStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
index 38709ec..652663e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
@@ -58,7 +58,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mScreenOffBrightnessModeStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
index f523b6a..0022cab 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
@@ -60,7 +60,8 @@
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mTemporaryBrightnessStrategy.updateBrightness(
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
-                                /* userSetBrightnessChanged= */ false));
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
         assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt
index b2d83d7..9a93fba 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt
@@ -43,35 +43,42 @@
     @Test
     fun testAppSupportedModes(@TestParameter testCase: AppSupportedModesTestCase) {
         whenever(mockFlags.isSynthetic60HzModesEnabled).thenReturn(testCase.syntheticModesEnabled)
+        whenever(mockFlags.hasArrSupportFlag()).thenReturn(testCase.hasArrSupport)
         whenever(mockConfig.isVrrSupportEnabled).thenReturn(testCase.vrrSupported)
         val syntheticModeManager = SyntheticModeManager(mockFlags)
 
         val result = syntheticModeManager.createAppSupportedModes(
-            mockConfig, testCase.supportedModes)
+            mockConfig, testCase.supportedModes, testCase.hasArrSupport)
 
         assertThat(result).isEqualTo(testCase.expectedAppModes)
     }
 
+    // TODO(b/361433651) Remove vrrSupported once hasArrSupport is rolled out
     enum class AppSupportedModesTestCase(
         val syntheticModesEnabled: Boolean,
         val vrrSupported: Boolean,
+        val hasArrSupport: Boolean,
         val supportedModes: Array<Mode>,
         val expectedAppModes: Array<Mode>
     ) {
-        SYNTHETIC_MODES_NOT_SUPPORTED(false, true, DISPLAY_MODES, DISPLAY_MODES),
-        VRR_NOT_SUPPORTED(true, false, DISPLAY_MODES, DISPLAY_MODES),
-        VRR_SYNTHETIC_NOT_SUPPORTED(false, false, DISPLAY_MODES, DISPLAY_MODES),
-        SINGLE_RESOLUTION_MODES(true, true, DISPLAY_MODES, arrayOf(
+        SYNTHETIC_MODES_NOT_SUPPORTED(false, true, true, DISPLAY_MODES, DISPLAY_MODES),
+        VRR_NOT_SUPPORTED(true, false, false, DISPLAY_MODES, DISPLAY_MODES),
+        VRR_SYNTHETIC_NOT_SUPPORTED(false, false, false, DISPLAY_MODES, DISPLAY_MODES),
+        SINGLE_RESOLUTION_MODES(true, true, true, DISPLAY_MODES, arrayOf(
             Mode(2, 100, 100, 120f),
             Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf())
         )),
-        NO_60HZ_MODES(true, true, arrayOf(Mode(2, 100, 100, 120f)),
+        SINGLE_RESOLUTION_MODES_HASARR(true, false, true, DISPLAY_MODES, arrayOf(
+            Mode(2, 100, 100, 120f),
+            Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf())
+        )),
+        NO_60HZ_MODES(true, true, true, arrayOf(Mode(2, 100, 100, 120f)),
             arrayOf(
                 Mode(2, 100, 100, 120f),
                 Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf())
             )
         ),
-        MULTI_RESOLUTION_MODES(true, true,
+        MULTI_RESOLUTION_MODES(true, true, true,
             arrayOf(
                 Mode(1, 100, 100, 120f),
                 Mode(2, 200, 200, 60f),
@@ -86,7 +93,7 @@
                 Mode(7, 300, 300, 60f, 60f, true, floatArrayOf(), intArrayOf())
             )
         ),
-        WITH_HDR_TYPES(true, true,
+        WITH_HDR_TYPES(true, true, true,
             arrayOf(
                 Mode(1, 100, 100, 120f, 120f, false, floatArrayOf(), intArrayOf(1, 2)),
                 Mode(2, 200, 200, 60f, 120f, false, floatArrayOf(), intArrayOf(3, 4)),
@@ -99,7 +106,7 @@
                 Mode(5, 200, 200, 60f, 60f, true, floatArrayOf(), intArrayOf(5, 6)),
             )
         ),
-        UNACHIEVABLE_60HZ(true, true,
+        UNACHIEVABLE_60HZ(true, true, true,
             arrayOf(
                 Mode(1, 100, 100, 90f),
             ),
@@ -107,7 +114,7 @@
                 Mode(1, 100, 100, 90f),
             )
         ),
-        MULTI_RESOLUTION_MODES_WITH_UNACHIEVABLE_60HZ(true, true,
+        MULTI_RESOLUTION_MODES_WITH_UNACHIEVABLE_60HZ(true, true, true,
             arrayOf(
                 Mode(1, 100, 100, 120f),
                 Mode(2, 200, 200, 90f),
@@ -118,7 +125,7 @@
                 Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf()),
             )
         ),
-        LOWER_THAN_60HZ_MODES(true, true,
+        LOWER_THAN_60HZ_MODES(true, true, true,
             arrayOf(
                 Mode(1, 100, 100, 30f),
                 Mode(2, 100, 100, 45f),
diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
index 1211456..439243e 100644
--- a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
+++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
@@ -82,6 +82,11 @@
     private static final AudioDeviceInfo FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET =
             createAudioDeviceInfo(
                     AudioSystem.DEVICE_OUT_WIRED_HEADSET, "name_wired_hs", /* address= */ null);
+    private static final AudioDeviceInfo FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET_WITH_ADDRESS =
+            createAudioDeviceInfo(
+                    AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+                    "name_wired_hs_with_address",
+                    /* address= */ "card=1;device=0");
     private static final AudioDeviceInfo FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP =
             createAudioDeviceInfo(
                     AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "name_a2dp", /* address= */ "12:34:45");
@@ -304,6 +309,55 @@
         assertThat(selectedRoute.getName().toString()).isEqualTo(FAKE_ROUTE_NAME);
     }
 
+    @Test
+    public void getAvailableRoutes_whenAddressIsPopulatedForNonBluetoothDevice_usesCorrectName() {
+        addAvailableAudioDeviceInfo(
+                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET_WITH_ADDRESS,
+                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET_WITH_ADDRESS,
+                FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP);
+
+        List<MediaRoute2Info> availableRoutes = mControllerUnderTest.getAvailableRoutes();
+        assertThat(availableRoutes.size()).isEqualTo(3);
+
+        assertThat(
+                        getAvailableRouteWithType(MediaRoute2Info.TYPE_WIRED_HEADSET)
+                                .getName()
+                                .toString())
+                .isEqualTo(
+                        FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET_WITH_ADDRESS
+                                .getProductName()
+                                .toString());
+
+        assertThat(
+                        getAvailableRouteWithType(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)
+                                .getName()
+                                .toString())
+                .isEqualTo(FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP.getProductName().toString());
+    }
+
+    @Test
+    public void
+            getAvailableRoutes_whenAddressIsNotPopulatedForNonBluetoothDevice_usesCorrectName() {
+        addAvailableAudioDeviceInfo(
+                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET,
+                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET);
+
+        List<MediaRoute2Info> availableRoutes = mControllerUnderTest.getAvailableRoutes();
+        assertThat(availableRoutes.size()).isEqualTo(2);
+
+        assertThat(
+                        getAvailableRouteWithType(MediaRoute2Info.TYPE_BUILTIN_SPEAKER)
+                                .getName()
+                                .toString())
+                .isEqualTo(FAKE_AUDIO_DEVICE_INFO_BUILTIN_SPEAKER.getProductName().toString());
+
+        assertThat(
+                        getAvailableRouteWithType(MediaRoute2Info.TYPE_WIRED_HEADSET)
+                                .getName()
+                                .toString())
+                .isEqualTo(FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET.getProductName().toString());
+    }
+
     // Internal methods.
 
     @NonNull
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 31157f9..9781851 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -95,7 +95,6 @@
 import com.android.server.job.JobStore;
 import com.android.server.job.controllers.QuotaController.ExecutionStats;
 import com.android.server.job.controllers.QuotaController.QcConstants;
-import com.android.server.job.controllers.QuotaController.QuotaBump;
 import com.android.server.job.controllers.QuotaController.ShrinkableDebits;
 import com.android.server.job.controllers.QuotaController.TimedEvent;
 import com.android.server.job.controllers.QuotaController.TimingSession;
@@ -136,7 +135,6 @@
     private QuotaController.QcConstants mQcConstants;
     private JobSchedulerService.Constants mConstants = new JobSchedulerService.Constants();
     private int mSourceUid;
-    private AppStandbyInternal.AppIdleStateChangeListener mAppIdleStateChangeListener;
     private PowerAllowlistInternal.TempAllowlistChangeListener mTempAllowlistListener;
     private IUidObserver mUidObserver;
     private UsageStatsManagerInternal.UsageEventListener mUsageEventListener;
@@ -191,8 +189,7 @@
         when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
         doReturn(mActivityMangerInternal)
                 .when(() -> LocalServices.getService(ActivityManagerInternal.class));
-        final AppStandbyInternal appStandbyInternal = mock(AppStandbyInternal.class);
-        doReturn(appStandbyInternal)
+        doReturn(mock(AppStandbyInternal.class))
                 .when(() -> LocalServices.getService(AppStandbyInternal.class));
         doReturn(mock(BatteryManagerInternal.class))
                 .when(() -> LocalServices.getService(BatteryManagerInternal.class));
@@ -239,8 +236,6 @@
 
         // Initialize real objects.
         // Capture the listeners.
-        ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> aiscListenerCaptor =
-                ArgumentCaptor.forClass(AppStandbyInternal.AppIdleStateChangeListener.class);
         ArgumentCaptor<IUidObserver> uidObserverCaptor =
                 ArgumentCaptor.forClass(IUidObserver.class);
         ArgumentCaptor<PowerAllowlistInternal.TempAllowlistChangeListener> taChangeCaptor =
@@ -250,8 +245,6 @@
         mQuotaController = new QuotaController(mJobSchedulerService,
                 mock(BackgroundJobsController.class), mock(ConnectivityController.class));
 
-        verify(appStandbyInternal).addListener(aiscListenerCaptor.capture());
-        mAppIdleStateChangeListener = aiscListenerCaptor.getValue();
         verify(mPowerAllowlistInternal)
                 .registerTempAllowlistChangeListener(taChangeCaptor.capture());
         mTempAllowlistListener = taChangeCaptor.getValue();
@@ -488,14 +481,12 @@
                 now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3);
         TimingSession two = createTimingSession(
                 now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
-        QuotaBump bump1 = new QuotaBump(now - 2 * HOUR_IN_MILLIS);
         TimingSession thr = createTimingSession(
                 now - (3 * HOUR_IN_MILLIS + 10 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
         // Overlaps 24 hour boundary.
         TimingSession fou = createTimingSession(
                 now - (24 * HOUR_IN_MILLIS + 2 * MINUTE_IN_MILLIS), 7 * MINUTE_IN_MILLIS, 1);
         // Way past the 24 hour boundary.
-        QuotaBump bump2 = new QuotaBump(now - 24 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
         TimingSession fiv = createTimingSession(
                 now - (25 * HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 4);
         List<TimedEvent> expectedRegular = new ArrayList<>();
@@ -503,16 +494,13 @@
         // Added in correct (chronological) order.
         expectedRegular.add(fou);
         expectedRegular.add(thr);
-        expectedRegular.add(bump1);
         expectedRegular.add(two);
         expectedRegular.add(one);
         expectedEJ.add(fou);
         expectedEJ.add(one);
         mQuotaController.saveTimingSession(0, "com.android.test", fiv, false);
-        mQuotaController.getTimingSessions(0, "com.android.test").add(bump2);
         mQuotaController.saveTimingSession(0, "com.android.test", fou, false);
         mQuotaController.saveTimingSession(0, "com.android.test", thr, false);
-        mQuotaController.getTimingSessions(0, "com.android.test").add(bump1);
         mQuotaController.saveTimingSession(0, "com.android.test", two, false);
         mQuotaController.saveTimingSession(0, "com.android.test", one, false);
         mQuotaController.saveTimingSession(0, "com.android.test", fiv, true);
@@ -1847,129 +1835,6 @@
         }
     }
 
-    /**
-     * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
-     * window and there are valid QuotaBumps in the history.
-     */
-    @Test
-    public void testGetTimeUntilQuotaConsumedLocked_QuotaBump() {
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS, MINUTE_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 8 * HOUR_IN_MILLIS);
-
-        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        // Close to RARE boundary.
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (24 * HOUR_IN_MILLIS - 30 * SECOND_IN_MILLIS),
-                        30 * SECOND_IN_MILLIS, 5), false);
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 16 * HOUR_IN_MILLIS));
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 12 * HOUR_IN_MILLIS));
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 8 * HOUR_IN_MILLIS));
-        // Far away from FREQUENT boundary.
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
-        // Overlap WORKING_SET boundary.
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 2 * HOUR_IN_MILLIS));
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS, 5), false);
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 15 * MINUTE_IN_MILLIS));
-        // Close to ACTIVE boundary.
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
-
-        setStandbyBucket(RARE_INDEX);
-        synchronized (mQuotaController.mLock) {
-            assertEquals(3 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
-                    mQuotaController.getRemainingExecutionTimeLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-            assertEquals(4 * MINUTE_IN_MILLIS,
-                    mQuotaController.getTimeUntilQuotaConsumedLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-        }
-
-        setStandbyBucket(FREQUENT_INDEX);
-        synchronized (mQuotaController.mLock) {
-            assertEquals(4 * MINUTE_IN_MILLIS,
-                    mQuotaController.getRemainingExecutionTimeLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-            assertEquals(4 * MINUTE_IN_MILLIS,
-                    mQuotaController.getTimeUntilQuotaConsumedLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-        }
-
-        setStandbyBucket(WORKING_INDEX);
-        synchronized (mQuotaController.mLock) {
-            assertEquals(8 * MINUTE_IN_MILLIS,
-                    mQuotaController.getRemainingExecutionTimeLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-            assertEquals(10 * MINUTE_IN_MILLIS,
-                    mQuotaController.getTimeUntilQuotaConsumedLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-        }
-
-        // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the
-        // max execution time.
-        setStandbyBucket(ACTIVE_INDEX);
-        synchronized (mQuotaController.mLock) {
-            assertEquals(10 * MINUTE_IN_MILLIS,
-                    mQuotaController.getRemainingExecutionTimeLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-            assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
-                    mQuotaController.getTimeUntilQuotaConsumedLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-        }
-    }
-
-    /**
-     * Test getTimeUntilQuotaConsumedLocked when there are valid QuotaBumps in recent history that
-     * provide enough additional quota to bridge gaps between sessions.
-     */
-    @Test
-    public void testGetTimeUntilQuotaConsumedLocked_QuotaBump_CrucialBumps() {
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS, MINUTE_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 8 * HOUR_IN_MILLIS);
-
-        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (25 * HOUR_IN_MILLIS),
-                        30 * MINUTE_IN_MILLIS, 25), false);
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 16 * HOUR_IN_MILLIS));
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 12 * HOUR_IN_MILLIS));
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 8 * HOUR_IN_MILLIS));
-        // Without the valid quota bumps, the app would only 3 minutes until the quota was consumed.
-        // The quota bumps provide enough quota to bridge the gap between the two earliest sessions.
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (8 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1), false);
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (8 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS),
-                        2 * MINUTE_IN_MILLIS, 5), false);
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS, 1), false);
-        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)
-                .add(new QuotaBump(now - 15 * MINUTE_IN_MILLIS));
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (9 * MINUTE_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 1), false);
-
-        setStandbyBucket(FREQUENT_INDEX);
-        synchronized (mQuotaController.mLock) {
-            assertEquals(2 * MINUTE_IN_MILLIS,
-                    mQuotaController.getRemainingExecutionTimeLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-            assertEquals(7 * MINUTE_IN_MILLIS,
-                    mQuotaController.getTimeUntilQuotaConsumedLocked(
-                            SOURCE_USER_ID, SOURCE_PACKAGE));
-        }
-    }
-
     @Test
     public void testIsWithinQuotaLocked_NeverApp() {
         synchronized (mQuotaController.mLock) {
@@ -2316,272 +2181,6 @@
         }
     }
 
-    @Test
-    public void testIsWithinQuotaLocked_WithQuotaBump_Duration() {
-        setDischarging();
-        int standbyBucket = WORKING_INDEX;
-        setStandbyBucket(standbyBucket);
-        setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_WORKING_MS,
-                5 * MINUTE_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_WORKING, 10);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS, MINUTE_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, 0);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT, 0);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 8 * HOUR_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_LIMIT, 5);
-
-        long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(
-                        now - (HOUR_IN_MILLIS - 2 * MINUTE_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 1),
-                false);
-        final ExecutionStats stats;
-        synchronized (mQuotaController.mLock) {
-            stats = mQuotaController.getExecutionStatsLocked(
-                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
-            mQuotaController.incrementJobCountLocked(SOURCE_USER_ID, SOURCE_PACKAGE, 1);
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(5 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-        }
-        mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(6 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-        }
-
-        advanceElapsedClock(HOUR_IN_MILLIS);
-
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(6 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-        }
-
-        // Emulate a quota bump while some jobs are executing
-        JobStatus job1 = createJobStatus("testIsWithinQuotaLocked_WithQuotaBump_Duration", 1);
-        JobStatus job2 = createJobStatus("testIsWithinQuotaLocked_WithQuotaBump_Duration", 2);
-
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStartTrackingJobLocked(job1, null);
-            mQuotaController.prepareForExecutionLocked(job1);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(7 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-            mQuotaController.maybeStartTrackingJobLocked(job2, null);
-            mQuotaController.prepareForExecutionLocked(job2);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStopTrackingJobLocked(job1, null);
-            mQuotaController.maybeStopTrackingJobLocked(job2, null);
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(7 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-        }
-
-        // Phase out the first session
-        advanceElapsedClock(5 * MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(7 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-        }
-
-        // Phase out the first quota bump
-        advanceElapsedClock(7 * HOUR_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(6 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
-        }
-    }
-
-    @Test
-    public void testIsWithinQuotaLocked_WithQuotaBump_JobCount() {
-        setDischarging();
-        int standbyBucket = WORKING_INDEX;
-        setStandbyBucket(standbyBucket);
-        setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_WORKING_MS,
-                20 * MINUTE_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_WORKING, 10);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS, 0);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, 1);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT, 0);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 8 * HOUR_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_LIMIT, 5);
-
-        long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (mQcConstants.WINDOW_SIZE_WORKING_MS - HOUR_IN_MILLIS),
-                        5 * MINUTE_IN_MILLIS, 10), false);
-        final ExecutionStats stats;
-        synchronized (mQuotaController.mLock) {
-            stats = mQuotaController.getExecutionStatsLocked(
-                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
-            mQuotaController.incrementJobCountLocked(SOURCE_USER_ID, SOURCE_PACKAGE, 10);
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(10, stats.jobCountLimit);
-        }
-        mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(11, stats.jobCountLimit);
-        }
-
-        advanceElapsedClock(HOUR_IN_MILLIS);
-
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(11, stats.jobCountLimit);
-        }
-
-        // Emulate a quota bump while some jobs are executing
-        JobStatus job1 = createJobStatus("testIsWithinQuotaLocked_WithQuotaBump_JobCount", 1);
-        JobStatus job2 = createJobStatus("testIsWithinQuotaLocked_WithQuotaBump_JobCount", 2);
-
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStartTrackingJobLocked(job1, null);
-            mQuotaController.prepareForExecutionLocked(job1);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(12, stats.jobCountLimit);
-            mQuotaController.maybeStartTrackingJobLocked(job2, null);
-            mQuotaController.prepareForExecutionLocked(job2);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStopTrackingJobLocked(job1, null);
-            mQuotaController.maybeStopTrackingJobLocked(job2, null);
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(12, stats.jobCountLimit);
-        }
-
-        // Phase out the first session
-        advanceElapsedClock(3 * MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(12, stats.jobCountLimit);
-        }
-
-        // Phase out the first quota bump
-        advanceElapsedClock(7 * HOUR_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(11, stats.jobCountLimit);
-        }
-    }
-
-    @Test
-    public void testIsWithinQuotaLocked_WithQuotaBump_SessionCount() {
-        setDischarging();
-        int standbyBucket = WORKING_INDEX;
-        setStandbyBucket(standbyBucket);
-        setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_WORKING_MS,
-                20 * MINUTE_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_WORKING, 2);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS, 0);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, 0);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT, 1);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 8 * HOUR_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_LIMIT, 5);
-
-        long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (mQcConstants.WINDOW_SIZE_WORKING_MS - HOUR_IN_MILLIS),
-                        5 * MINUTE_IN_MILLIS, 1), false);
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (30 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1), false);
-        final ExecutionStats stats;
-        synchronized (mQuotaController.mLock) {
-            stats = mQuotaController.getExecutionStatsLocked(
-                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(2, stats.sessionCountLimit);
-        }
-        mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(3, stats.sessionCountLimit);
-        }
-
-        advanceElapsedClock(HOUR_IN_MILLIS);
-
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(3, stats.sessionCountLimit);
-        }
-
-        // Emulate a quota bump while some jobs are executing
-        JobStatus job1 = createJobStatus("testIsWithinQuotaLocked_WithQuotaBump_JobCount", 1);
-        JobStatus job2 = createJobStatus("testIsWithinQuotaLocked_WithQuotaBump_JobCount", 2);
-
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStartTrackingJobLocked(job1, null);
-            mQuotaController.prepareForExecutionLocked(job1);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStopTrackingJobLocked(job1, null);
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(4, stats.sessionCountLimit);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStartTrackingJobLocked(job2, null);
-            mQuotaController.prepareForExecutionLocked(job2);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStopTrackingJobLocked(job2, null);
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(4, stats.sessionCountLimit);
-        }
-
-        // Phase out the first session
-        advanceElapsedClock(2 * MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(4, stats.sessionCountLimit);
-        }
-
-        // Phase out the first quota bump
-        advanceElapsedClock(7 * HOUR_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(3, stats.sessionCountLimit);
-        }
-    }
 
     @Test
     public void testIsWithinEJQuotaLocked_NeverApp() {
@@ -3590,12 +3189,6 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS,
                 84 * SECOND_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 83 * SECOND_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS,
-                93 * SECOND_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, 92);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT, 91);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 90 * MINUTE_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_LIMIT, 89);
 
         assertEquals(8 * MINUTE_IN_MILLIS,
                 mQuotaController.getAllowedTimePerPeriodMs()[EXEMPTED_INDEX]);
@@ -3653,11 +3246,6 @@
         assertEquals(85 * SECOND_IN_MILLIS, mQuotaController.getEJRewardNotificationSeenMs());
         assertEquals(84 * SECOND_IN_MILLIS, mQuotaController.getEJGracePeriodTempAllowlistMs());
         assertEquals(83 * SECOND_IN_MILLIS, mQuotaController.getEJGracePeriodTopAppMs());
-        assertEquals(93 * SECOND_IN_MILLIS, mQuotaController.getQuotaBumpAdditionDurationMs());
-        assertEquals(92, mQuotaController.getQuotaBumpAdditionJobCount());
-        assertEquals(91, mQuotaController.getQuotaBumpAdditionSessionCount());
-        assertEquals(90 * MINUTE_IN_MILLIS, mQuotaController.getQuotaBumpWindowSizeMs());
-        assertEquals(89, mQuotaController.getQuotaBumpLimit());
     }
 
     @Test
@@ -3710,11 +3298,6 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, -1);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_DURATION_MS, -1);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_JOB_COUNT, -1);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_ADDITIONAL_SESSION_COUNT, -1);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 59 * MINUTE_IN_MILLIS);
-        setDeviceConfigInt(QcConstants.KEY_QUOTA_BUMP_LIMIT, -1);
 
         assertEquals(MINUTE_IN_MILLIS,
                 mQuotaController.getAllowedTimePerPeriodMs()[EXEMPTED_INDEX]);
@@ -3765,11 +3348,6 @@
         assertEquals(0, mQuotaController.getEJRewardNotificationSeenMs());
         assertEquals(0, mQuotaController.getEJGracePeriodTempAllowlistMs());
         assertEquals(0, mQuotaController.getEJGracePeriodTopAppMs());
-        assertEquals(0, mQuotaController.getQuotaBumpAdditionDurationMs());
-        assertEquals(0, mQuotaController.getQuotaBumpAdditionJobCount());
-        assertEquals(0, mQuotaController.getQuotaBumpAdditionSessionCount());
-        assertEquals(60 * MINUTE_IN_MILLIS, mQuotaController.getQuotaBumpWindowSizeMs());
-        assertEquals(0, mQuotaController.getQuotaBumpLimit());
 
         // Invalid configurations.
         // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD
@@ -3827,7 +3405,6 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_QUOTA_BUMP_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS);
 
         assertEquals(24 * HOUR_IN_MILLIS,
                 mQuotaController.getAllowedTimePerPeriodMs()[EXEMPTED_INDEX]);
@@ -3868,7 +3445,6 @@
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardNotificationSeenMs());
         assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJGracePeriodTempAllowlistMs());
         assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJGracePeriodTopAppMs());
-        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getQuotaBumpWindowSizeMs());
     }
 
     /** Tests that TimingSessions aren't saved when the device is charging. */
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
index 9ba2724..625dbe6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
@@ -18,6 +18,7 @@
 
 import static android.media.AudioAttributes.USAGE_ALARM;
 
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -91,6 +92,7 @@
     }
     @Test
     public void testAlarmOnBackgroundUser_foregroundUserNotified() throws RemoteException {
+        assumeTrue(UserManager.supportsMultipleUsers());
         AudioAttributes aa = new AudioAttributes.Builder().setUsage(USAGE_ALARM).build();
         UserInfo user = createUser("User", UserManager.USER_TYPE_FULL_SECONDARY, 0);
         final int fgUserId = mSpiedContext.getUserId();
@@ -100,7 +102,7 @@
                 /* packageName= */ "com.android.car.audio", AudioManager.AUDIOFOCUS_GAIN,
                 AudioManager.AUDIOFOCUS_NONE, /* flags= */ 0, Build.VERSION.SDK_INT);
         clearInvocations(mNotificationManager);
-        mBackgroundUserSoundNotifier.notifyForegroundUserAboutSoundIfNecessary(afi, mSpiedContext);
+        mBackgroundUserSoundNotifier.notifyForegroundUserAboutSoundIfNecessary(afi);
         verify(mNotificationManager)
                 .notifyAsUser(eq(BackgroundUserSoundNotifier.class.getSimpleName()),
                         eq(afi.getClientUid()), any(Notification.class),
@@ -116,7 +118,7 @@
                 /* packageName= */ "com.android.car.audio", AudioManager.AUDIOFOCUS_GAIN,
                 AudioManager.AUDIOFOCUS_NONE, /* flags= */ 0, Build.VERSION.SDK_INT);
         clearInvocations(mNotificationManager);
-        mBackgroundUserSoundNotifier.notifyForegroundUserAboutSoundIfNecessary(afi, mSpiedContext);
+        mBackgroundUserSoundNotifier.notifyForegroundUserAboutSoundIfNecessary(afi);
         verifyZeroInteractions(mNotificationManager);
     }
 
@@ -131,7 +133,7 @@
                 AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_NONE, /* flags= */ 0,
                 Build.VERSION.SDK_INT);
         clearInvocations(mNotificationManager);
-        mBackgroundUserSoundNotifier.notifyForegroundUserAboutSoundIfNecessary(afi, mSpiedContext);
+        mBackgroundUserSoundNotifier.notifyForegroundUserAboutSoundIfNecessary(afi);
         verifyZeroInteractions(mNotificationManager);
     }
 
@@ -169,7 +171,7 @@
         doReturn(focusStack).when(mockAudioPolicy).getFocusStack();
         mBackgroundUserSoundNotifier.mFocusControlAudioPolicy = mockAudioPolicy;
 
-        mBackgroundUserSoundNotifier.muteAlarmSounds(mSpiedContext);
+        mBackgroundUserSoundNotifier.muteAlarmSounds(bgUserUid);
 
         verify(apc1.getPlayerProxy()).stop();
         verify(mockAudioPolicy).sendFocusLossAndUpdate(afi);
@@ -178,6 +180,7 @@
 
     @Test
     public void testOnAudioFocusGrant_alarmOnBackgroundUser_notifiesForegroundUser() {
+        assumeTrue(UserManager.supportsMultipleUsers());
         final int fgUserId = mSpiedContext.getUserId();
         UserInfo bgUser = createUser("Background User",  UserManager.USER_TYPE_FULL_SECONDARY, 0);
         int bgUserUid = bgUser.id * 100000;
@@ -205,7 +208,7 @@
                 .when(mUserManager).getUserSwitchability(any());
 
         Notification notification = mBackgroundUserSoundNotifier.createNotification(userName,
-                mSpiedContext);
+                mSpiedContext, 101000);
 
         assertEquals("Alarm for BgUser", notification.extras.getString(
                 Notification.EXTRA_TITLE));
@@ -232,7 +235,7 @@
                 .when(mUserManager).getUserSwitchability(any());
 
         Notification notification = mBackgroundUserSoundNotifier.createNotification(userName,
-                mSpiedContext);
+                mSpiedContext, 101000);
 
         assertEquals(1, notification.actions.length);
         assertEquals(mSpiedContext.getString(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index 39acd8d..43a8aa9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -72,7 +72,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Predicate;
 
@@ -486,7 +485,7 @@
             FakeStagedSession session = new FakeStagedSession(239);
             session.setIsApex(true);
             // Call and verify
-            Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(session);
+            var result = mStagingManager.getStagedApexInfos(session);
             assertThat(result).isEmpty();
         }
         // Invalid session: destroyed
@@ -496,7 +495,7 @@
             session.setIsApex(true);
             session.setDestroyed(true);
             // Call and verify
-            Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(session);
+            var result = mStagingManager.getStagedApexInfos(session);
             assertThat(result).isEmpty();
         }
     }
@@ -520,8 +519,8 @@
         when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
 
         // Call and verify
-        Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(validSession);
-        assertThat(result).containsExactly(fakeApexInfos[0].moduleName, fakeApexInfos[0]);
+        List<ApexInfo> result = mStagingManager.getStagedApexInfos(validSession);
+        assertThat(result).containsExactly(fakeApexInfos[0]);
 
         ArgumentCaptor<ApexSessionParams> argumentCaptor =
                 ArgumentCaptor.forClass(ApexSessionParams.class);
@@ -544,9 +543,8 @@
         when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
 
         // Call and verify
-        Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(parentSession);
-        assertThat(result).containsExactly(fakeApexInfos[0].moduleName, fakeApexInfos[0],
-                fakeApexInfos[1].moduleName, fakeApexInfos[1]);
+        List<ApexInfo> result = mStagingManager.getStagedApexInfos(parentSession);
+        assertThat(result).containsExactly(fakeApexInfos[0], fakeApexInfos[1]);
 
         ArgumentCaptor<ApexSessionParams> argumentCaptor =
                 ArgumentCaptor.forClass(ApexSessionParams.class);
@@ -557,7 +555,7 @@
     }
 
     @Test
-    public void getStagedApexModuleNames_returnsStagedApexModules() throws Exception {
+    public void getStagedApexInfos_returnsStagedApexModules() throws Exception {
         FakeStagedSession validSession1 = new FakeStagedSession(239);
         validSession1.setIsApex(true);
         validSession1.setSessionReady();
@@ -575,8 +573,8 @@
 
         mockApexManagerGetStagedApexInfoWithSessionId();
 
-        List<String> result = mStagingManager.getStagedApexModuleNames();
-        assertThat(result).containsExactly("239", "123", "124");
+        List<StagedApexInfo> result = mStagingManager.getStagedApexInfos();
+        assertThat(result).containsExactly((Object[]) fakeStagedApexInfos("239", "123", "124"));
         verify(mApexManager, times(2)).getStagedApexInfos(any());
     }
 
@@ -605,26 +603,12 @@
         });
     }
 
-    @Test
-    public void getStagedApexInfo() throws Exception {
-        FakeStagedSession validSession1 = new FakeStagedSession(239);
-        validSession1.setIsApex(true);
-        validSession1.setSessionReady();
-        mStagingManager.createSession(validSession1);
-        ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1"));
-        when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
-
-        // Verify null is returned if module name is not found
-        StagedApexInfo result = mStagingManager.getStagedApexInfo("not found");
-        assertThat(result).isNull();
-        verify(mApexManager, times(1)).getStagedApexInfos(any());
-        // Otherwise, the correct object is returned
-        result = mStagingManager.getStagedApexInfo("module1");
-        assertThat(result.moduleName).isEqualTo(fakeApexInfos[0].moduleName);
-        assertThat(result.diskImagePath).isEqualTo(fakeApexInfos[0].modulePath);
-        assertThat(result.versionCode).isEqualTo(fakeApexInfos[0].versionCode);
-        assertThat(result.versionName).isEqualTo(fakeApexInfos[0].versionName);
-        verify(mApexManager, times(2)).getStagedApexInfos(any());
+    private StagedApexInfo[] fakeStagedApexInfos(String... moduleNames) {
+        return Arrays.stream(moduleNames).map(moduleName -> {
+            StagedApexInfo info = new StagedApexInfo();
+            info.moduleName = moduleName;
+            return info;
+        }).toArray(StagedApexInfo[]::new);
     }
 
     @Test
@@ -646,8 +630,8 @@
             ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
                     ApexStagedEvent.class);
             verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
-            assertThat(argumentCaptor.getValue().stagedApexModuleNames).isEqualTo(
-                    new String[]{"239"});
+            assertThat(argumentCaptor.getValue().stagedApexInfos).isEqualTo(
+                    fakeStagedApexInfos("239"));
         }
 
         // Create another staged session and verify observers are notified of union
@@ -662,8 +646,8 @@
             ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
                     ApexStagedEvent.class);
             verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
-            assertThat(argumentCaptor.getValue().stagedApexModuleNames).isEqualTo(
-                    new String[]{"239", "240"});
+            assertThat(argumentCaptor.getValue().stagedApexInfos).isEqualTo(
+                    fakeStagedApexInfos("239", "240"));
         }
 
         // Finally, verify that once unregistered, observer is not notified
@@ -699,7 +683,7 @@
         ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
                 ApexStagedEvent.class);
         verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
-        assertThat(argumentCaptor.getValue().stagedApexModuleNames).hasLength(0);
+        assertThat(argumentCaptor.getValue().stagedApexInfos).hasLength(0);
     }
 
     @Test
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 639ae30..58489f3 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -81,7 +81,6 @@
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -581,8 +580,6 @@
         HintManagerService service = createService();
         IBinder token = new Binder();
         int threadCount = 2;
-
-        // session 1 has 2 non-isolated tids
         long sessionPtr1 = 111;
         CountDownLatch stopLatch1 = new CountDownLatch(1);
         int[] tids1 = createThreads(threadCount, stopLatch1);
@@ -618,7 +615,6 @@
         IBinder token = new Binder();
         int threadCount = 2;
 
-        // session 1 has 2 non-isolated tids
         long sessionPtr1 = 111;
         CountDownLatch stopLatch1 = new CountDownLatch(1);
         int[] tids1 = createThreads(threadCount, stopLatch1);
@@ -630,67 +626,23 @@
                         SessionTag.OTHER, new SessionConfig());
         assertNotNull(session1);
 
-        // session 2 has 2 non-isolated tids and 2 isolated tids
-        long sessionPtr2 = 222;
-        CountDownLatch stopLatch2 = new CountDownLatch(1);
-        // negative value used for test only to avoid conflicting with any real thread that exists
-        int isoProc1 = -100;
-        int isoProc2 = 99999999;
-        when(mAmInternalMock.getIsolatedProcesses(eq(UID))).thenReturn(List.of(0));
-        int[] tids2 = createThreads(threadCount, stopLatch2);
-        int[] tids2WithIsolated = Arrays.copyOf(tids2, tids2.length + 2);
-        tids2WithIsolated[threadCount] = isoProc1;
-        tids2WithIsolated[threadCount + 1] = isoProc2;
-        int[] expectedTids2 = Arrays.copyOf(tids2, tids2.length + 1);
-        expectedTids2[tids2.length] = isoProc1;
-        when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
-                eq(tids2WithIsolated), eq(DEFAULT_TARGET_DURATION), anyInt(),
-                any(SessionConfig.class))).thenReturn(sessionPtr2);
-        AppHintSession session2 = (AppHintSession) service.getBinderServiceInstance()
-                .createHintSessionWithConfig(token, tids2WithIsolated,
-                        DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
-        assertNotNull(session2);
-
-        // trigger clean up through UID state change by making the process foreground->background
-        // this will remove the one unexpected isolated tid from session 2
-        service.mUidObserver.onUidStateChanged(UID,
-                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
-        service.mUidObserver.onUidStateChanged(UID,
-                ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
-        LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000) + TimeUnit.MILLISECONDS.toNanos(
-                CLEAN_UP_UID_DELAY_MILLIS));
-        verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
-        verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
-        // the new TIDs pending list should be updated
-        assertArrayEquals(expectedTids2, session2.getTidsInternal());
-        reset(mNativeWrapperMock);
-
-        // this should resume and update the threads so those never-existed invalid isolated
-        // processes should be cleaned up
-        service.mUidObserver.onUidStateChanged(UID,
-                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
-        // wait for the async uid state change to trigger resume and setThreads
-        LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
-        verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr2), eq(expectedTids2));
-        reset(mNativeWrapperMock);
-
         // let all session 1 threads to exit and the cleanup should force pause the session 1
         stopLatch1.countDown();
         LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
         service.mUidObserver.onUidStateChanged(UID,
+                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
+        service.mUidObserver.onUidStateChanged(UID,
                 ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
         LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000) + TimeUnit.MILLISECONDS.toNanos(
                 CLEAN_UP_UID_DELAY_MILLIS));
         verify(mNativeWrapperMock, times(1)).halPauseHintSession(eq(sessionPtr1));
         verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
-        verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
         verifyAllHintsEnabled(session1, false);
-        verifyAllHintsEnabled(session2, false);
         service.mUidObserver.onUidStateChanged(UID,
                 ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
         LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
+        assertArrayEquals(tids1, session1.getTidsInternal());
         verifyAllHintsEnabled(session1, false);
-        verifyAllHintsEnabled(session2, true);
         reset(mNativeWrapperMock);
 
         // in foreground, set new tids for session 1 then it should be resumed and all hints allowed
@@ -704,8 +656,6 @@
 
         // let all session 1 and 2 non isolated threads to exit
         stopLatch1.countDown();
-        stopLatch2.countDown();
-        expectedTids2 = new int[]{isoProc1};
         LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
         service.mUidObserver.onUidStateChanged(UID,
                 ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
@@ -713,14 +663,11 @@
                 CLEAN_UP_UID_DELAY_MILLIS));
         verify(mNativeWrapperMock, times(1)).halPauseHintSession(eq(sessionPtr1));
         verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
-        verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
         // in background, set threads for session 1 then it should not be force paused next time
         session1.setThreads(SESSION_TIDS_A);
         // the new TIDs pending list should be updated
         assertArrayEquals(SESSION_TIDS_A, session1.getTidsInternal());
-        assertArrayEquals(expectedTids2, session2.getTidsInternal());
         verifyAllHintsEnabled(session1, false);
-        verifyAllHintsEnabled(session2, false);
         reset(mNativeWrapperMock);
 
         service.mUidObserver.onUidStateChanged(UID,
@@ -729,10 +676,7 @@
                 CLEAN_UP_UID_DELAY_MILLIS));
         verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr1),
                 eq(SESSION_TIDS_A));
-        verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr2),
-                eq(expectedTids2));
         verifyAllHintsEnabled(session1, true);
-        verifyAllHintsEnabled(session2, true);
     }
 
     private void verifyAllHintsEnabled(AppHintSession session, boolean verifyEnabled) {
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index a1db182..1c7fc63 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -54,6 +54,7 @@
 import android.provider.Settings;
 import android.testing.TestableContext;
 import android.util.IntArray;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.Display;
 import android.view.DisplayAddress;
@@ -384,6 +385,32 @@
     }
 
     @Test
+    public void testOnGroupRemoved_perDisplayWakeByTouchEnabled() {
+        createNotifier();
+        // GIVEN per-display wake by touch is enabled and one display group has been defined
+        when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(true);
+        final int groupId = 313;
+        final int displayId1 = 3113;
+        final int displayId2 = 4114;
+        final int[] displays = new int[]{displayId1, displayId2};
+        when(mDisplayManagerInternal.getDisplayIds()).thenReturn(IntArray.wrap(displays));
+        when(mDisplayManagerInternal.getDisplayIdsForGroup(groupId)).thenReturn(displays);
+        mNotifier.onGroupWakefulnessChangeStarted(
+                groupId, WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_TAP, /* eventTime= */ 1000);
+        final SparseBooleanArray expectedDisplayInteractivities = new SparseBooleanArray();
+        expectedDisplayInteractivities.put(displayId1, true);
+        expectedDisplayInteractivities.put(displayId2, true);
+        verify(mInputManagerInternal).setDisplayInteractivities(expectedDisplayInteractivities);
+
+        // WHEN display group is removed
+        when(mDisplayManagerInternal.getDisplayIdsByGroupsIds()).thenReturn(new SparseArray<>());
+        mNotifier.onGroupRemoved(groupId);
+
+        // THEN native input manager is informed that displays in that group no longer exist
+        verify(mInputManagerInternal).setDisplayInteractivities(new SparseBooleanArray());
+    }
+
+    @Test
     public void testOnWakeLockListener_RemoteException_NoRethrow() throws RemoteException {
         when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
         createNotifier();
diff --git a/services/tests/security/forensic/OWNERS b/services/tests/security/forensic/OWNERS
new file mode 100644
index 0000000..80c9afb9
--- /dev/null
+++ b/services/tests/security/forensic/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+file:platform/frameworks/base:main:/core/java/android/security/forensic/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
index 3e2949d6..de5564c 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
@@ -20,6 +20,8 @@
 import static com.android.media.audio.Flags.FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME;
 import static com.android.media.audio.Flags.absVolumeIndexFix;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -109,12 +111,13 @@
         mAudioService.setDeviceVolume(volMin, usbDevice, mPackageName);
         mTestLooper.dispatchAll();
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                        AudioManager.STREAM_MUSIC, minIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
+                eq(AudioManager.STREAM_MUSIC), eq(minIndex), anyBoolean(),
+                eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
 
         mAudioService.setDeviceVolume(volMid, usbDevice, mPackageName);
         mTestLooper.dispatchAll();
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                AudioManager.STREAM_MUSIC, midIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
+                AudioManager.STREAM_MUSIC, midIndex, false, AudioSystem.DEVICE_OUT_USB_DEVICE);
     }
 
     @Test
@@ -151,7 +154,7 @@
 
             // Stream volume changes
             verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                            AudioManager.STREAM_MUSIC, targetIndex,
+                            AudioManager.STREAM_MUSIC, targetIndex, false,
                             AudioSystem.DEVICE_OUT_BLE_HEADSET);
         }
 
@@ -162,7 +165,7 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                        AudioManager.STREAM_MUSIC, maxIndex,
+                        AudioManager.STREAM_MUSIC, maxIndex, false,
                         AudioSystem.DEVICE_OUT_BLE_HEADSET);
     }
 
@@ -193,8 +196,8 @@
             }
             // Stream volume changes
             verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                            AudioManager.STREAM_MUSIC, passedIndex,
-                            AudioSystem.DEVICE_OUT_BLE_HEADSET);
+                    AudioManager.STREAM_MUSIC, passedIndex, false,
+                    AudioSystem.DEVICE_OUT_BLE_HEADSET);
         }
 
         // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
@@ -207,7 +210,7 @@
             passedIndex = 4;
         }
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                        AudioManager.STREAM_MUSIC, passedIndex,
-                        AudioSystem.DEVICE_OUT_BLE_HEADSET);
+                AudioManager.STREAM_MUSIC, passedIndex, false,
+                AudioSystem.DEVICE_OUT_BLE_HEADSET);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 96ac5d2..ce59a86 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -132,12 +132,13 @@
     }
 
     @Override
-    public int setStreamVolumeIndexAS(int stream, int index, int device) {
+    public int setStreamVolumeIndexAS(int stream, int index, boolean muted, int device) {
         return AudioSystem.AUDIO_STATUS_OK;
     }
 
     @Override
-    public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, int device) {
+    public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, boolean muted,
+            int device) {
         return AudioSystem.AUDIO_STATUS_OK;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
index dc8c1b9..6b41c43 100644
--- a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
@@ -18,6 +18,7 @@
 import static android.media.AudioManager.ADJUST_LOWER;
 import static android.media.AudioManager.ADJUST_MUTE;
 import static android.media.AudioManager.ADJUST_RAISE;
+import static android.media.AudioManager.ADJUST_UNMUTE;
 import static android.media.AudioManager.DEVICE_OUT_BLE_SPEAKER;
 import static android.media.AudioManager.DEVICE_OUT_BLUETOOTH_SCO;
 import static android.media.AudioManager.DEVICE_OUT_SPEAKER;
@@ -41,13 +42,13 @@
 
 import static com.android.media.audio.Flags.FLAG_ABS_VOLUME_INDEX_FIX;
 import static com.android.media.audio.Flags.FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME;
+import static com.android.media.audio.Flags.FLAG_RING_MY_CAR;
 import static com.android.media.audio.Flags.absVolumeIndexFix;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
@@ -180,6 +181,10 @@
             }
             return mStreamDevice.get(stream);
         }
+
+        public void setMuteAffectedStreams(int muteAffectedStreams) {
+            mMuteAffectedStreams = muteAffectedStreams;
+        }
     }
 
     private static class TestDeviceVolumeBehaviorDispatcherStub
@@ -223,6 +228,7 @@
                 mSettingsAdapter, mAudioVolumeGroupHelper, mMockAudioPolicy,
                 mTestLooper.getLooper(), mMockAppOpsManager, mMockPermissionEnforcer,
                 mMockPermissionProvider);
+        mAudioService.setMuteAffectedStreams(AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED);
 
         mTestLooper.dispatchAll();
         prepareAudioServiceState();
@@ -258,6 +264,8 @@
         for (int streamType : usedStreamTypes) {
             mAudioService.setStreamVolume(streamType, DEFAULT_STREAM_VOLUME, /*flags=*/0,
                     mContext.getOpPackageName());
+            mAudioService.adjustStreamVolume(streamType, ADJUST_UNMUTE, /*flags=*/0,
+                    mContext.getOpPackageName());
         }
 
         if (!mIsAutomotive) {
@@ -301,7 +309,20 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem).setStreamVolumeIndexAS(
-                eq(STREAM_MUSIC), eq(newIndex), eq(DEVICE_OUT_USB_DEVICE));
+                STREAM_MUSIC, newIndex, /*muted=*/false, DEVICE_OUT_USB_DEVICE);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_RING_MY_CAR)
+    public void adjustStreamVolume_adjustMute_callsASSetStreamVolumeIndex() throws Exception {
+        int currentIndex = mAudioService.getStreamVolume(STREAM_MUSIC);
+
+        mAudioService.adjustStreamVolume(STREAM_MUSIC, ADJUST_MUTE, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem).setStreamVolumeIndexAS(
+                eq(STREAM_MUSIC), eq(currentIndex), /*muted=*/eq(true), anyInt());
     }
 
     @Test
@@ -325,7 +346,7 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                eq(STREAM_MUSIC), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+                eq(STREAM_MUSIC), anyInt(), anyBoolean(), eq(DEVICE_OUT_USB_DEVICE));
     }
 
     @Test
@@ -341,7 +362,7 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem).setStreamVolumeIndexAS(
-                eq(STREAM_MUSIC), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+                eq(STREAM_MUSIC), anyInt(), eq(false), eq(DEVICE_OUT_USB_DEVICE));
     }
 
     // --------------- Volume Group APIs ---------------
@@ -356,15 +377,15 @@
         mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
         mAudioService.setVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId(),
                 circularNoMinMaxIncrementVolume(STREAM_MUSIC), /*flags=*/0,
-                mContext.getOpPackageName(),  /*attributionTag*/null);
+                mContext.getOpPackageName(), /*attributionTag*/null);
         mTestLooper.dispatchAll();
 
-        verify(mSpyAudioSystem).setVolumeIndexForAttributes(any(), anyInt(),
+        verify(mSpyAudioSystem).setVolumeIndexForAttributes(any(), anyInt(), eq(false),
                 eq(DEVICE_OUT_USB_DEVICE));
     }
 
     @Test
-    public void adjustVolumeGroupVolume_callsASSetVolumeIndexForAttributes() throws Exception {
+    public void adjustVolumeGroupVolume_callsASSetStreamVolumeIndexAS() throws Exception {
         assumeNotNull(mAudioMusicVolumeGroup);
 
         mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -372,8 +393,24 @@
                 ADJUST_LOWER, /*flags=*/0, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
 
-        verify(mSpyAudioSystem).setVolumeIndexForAttributes(
-                any(), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+        // adjust calls setStreamVolumeIndexAS instead of setVolumeIndexForAttributes
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                anyInt(), anyInt(), anyBoolean(), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_RING_MY_CAR)
+    public void adjustVolumeGroupVolume_adjustMute_callsASSetStreamVolumeIndexAS()
+            throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        mAudioService.adjustVolumeGroupVolume(mAudioMusicVolumeGroup.getId(),
+                ADJUST_MUTE, /*flags=*/0, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        // adjust calls setStreamVolumeIndexAS instead of setVolumeIndexForAttributes
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                anyInt(), anyInt(), eq(true), anyInt());
     }
 
     @Test
@@ -437,7 +474,7 @@
 
     @Test
     public void check_isStreamAffectedByMute() {
-        assertFalse(mAudioService.isStreamAffectedByMute(STREAM_VOICE_CALL));
+        assertTrue(mAudioService.isStreamAffectedByMute(STREAM_VOICE_CALL));
     }
 
     // --------------------- Volume Flag Check --------------------
@@ -452,14 +489,14 @@
                 mContext.getOpPackageName());
         mTestLooper.dispatchAll();
         verify(mSpyAudioSystem).setStreamVolumeIndexAS(
-                eq(STREAM_NOTIFICATION), anyInt(), eq(DEVICE_OUT_BLE_SPEAKER));
+                eq(STREAM_NOTIFICATION), anyInt(), eq(false), eq(DEVICE_OUT_BLE_SPEAKER));
 
         reset(mSpyAudioSystem);
         mAudioService.adjustStreamVolume(STREAM_NOTIFICATION, ADJUST_LOWER,
                 FLAG_BLUETOOTH_ABS_VOLUME, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
         verify(mSpyAudioSystem).setStreamVolumeIndexAS(
-                eq(STREAM_NOTIFICATION), anyInt(), eq(DEVICE_OUT_BLE_SPEAKER));
+                eq(STREAM_NOTIFICATION), anyInt(), eq(false), eq(DEVICE_OUT_BLE_SPEAKER));
     }
 
     @Test
@@ -471,13 +508,13 @@
                 mContext.getOpPackageName());
         mTestLooper.dispatchAll();
         verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
-                eq(STREAM_NOTIFICATION), eq(newIndex), eq(DEVICE_OUT_BLE_SPEAKER));
+                eq(STREAM_NOTIFICATION), eq(newIndex), eq(false), eq(DEVICE_OUT_BLE_SPEAKER));
 
         mAudioService.adjustStreamVolume(STREAM_NOTIFICATION, ADJUST_LOWER,
                 FLAG_BLUETOOTH_ABS_VOLUME, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
         verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
-                eq(STREAM_NOTIFICATION), anyInt(), eq(DEVICE_OUT_BLE_SPEAKER));
+                eq(STREAM_NOTIFICATION), anyInt(), eq(false), eq(DEVICE_OUT_BLE_SPEAKER));
     }
 
     @Test
@@ -523,7 +560,7 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
-                eq(STREAM_MUSIC), anyInt(), anyInt());
+                eq(STREAM_MUSIC), anyInt(), eq(false), anyInt());
     }
 
     @Test
@@ -537,7 +574,7 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
-                eq(STREAM_VOICE_CALL), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+                eq(STREAM_VOICE_CALL), anyInt(), eq(false), eq(DEVICE_OUT_USB_DEVICE));
 
         mAudioService.setDeviceForStream(STREAM_BLUETOOTH_SCO, DEVICE_OUT_BLUETOOTH_SCO);
         mAudioService.adjustStreamVolume(STREAM_BLUETOOTH_SCO, ADJUST_MUTE, /*flags=*/0,
@@ -545,7 +582,7 @@
         mTestLooper.dispatchAll();
 
         verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
-                eq(STREAM_BLUETOOTH_SCO), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+                eq(STREAM_BLUETOOTH_SCO), anyInt(), eq(false), eq(DEVICE_OUT_USB_DEVICE));
     }
 
     // ----------------- AudioDeviceVolumeManager -----------------
@@ -568,18 +605,18 @@
         mTestLooper.dispatchAll();
 
         // there is a min/max index mismatch in automotive
-        assertEquals(volMin, mAudioService.getDeviceVolume(volMin, usbDevice,
-                mContext.getOpPackageName()));
+        assertEquals(volMin.getVolumeIndex(), mAudioService.getDeviceVolume(volMin, usbDevice,
+                mContext.getOpPackageName()).getVolumeIndex());
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                eq(STREAM_MUSIC), anyInt(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
+                eq(STREAM_MUSIC), anyInt(), anyBoolean(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
 
         mAudioService.setDeviceVolume(volMid, usbDevice, mContext.getOpPackageName());
         mTestLooper.dispatchAll();
         // there is a min/max index mismatch in automotive
-        assertEquals(volMid, mAudioService.getDeviceVolume(volMid, usbDevice,
-                mContext.getOpPackageName()));
+        assertEquals(volMid.getVolumeIndex(), mAudioService.getDeviceVolume(volMid, usbDevice,
+                mContext.getOpPackageName()).getVolumeIndex());
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                eq(STREAM_MUSIC), anyInt(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
+                eq(STREAM_MUSIC), anyInt(), anyBoolean(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
     }
 
     @Test
@@ -617,8 +654,7 @@
                     mAudioService.getDeviceVolume(volCur, bleDevice, mContext.getOpPackageName()));
             // Stream volume changes
             verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                    STREAM_MUSIC, targetIndex,
-                    AudioSystem.DEVICE_OUT_BLE_HEADSET);
+                    STREAM_MUSIC, targetIndex, false, AudioSystem.DEVICE_OUT_BLE_HEADSET);
         }
 
         // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
@@ -630,8 +666,7 @@
         assertEquals(volIndex4,
                 mAudioService.getDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName()));
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                STREAM_MUSIC, maxIndex,
-                AudioSystem.DEVICE_OUT_BLE_HEADSET);
+                STREAM_MUSIC, maxIndex, false, AudioSystem.DEVICE_OUT_BLE_HEADSET);
     }
 
     @Test
@@ -660,8 +695,7 @@
             }
             // Stream volume changes
             verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                    STREAM_MUSIC, passedIndex,
-                    AudioSystem.DEVICE_OUT_BLE_HEADSET);
+                    STREAM_MUSIC, passedIndex, false, AudioSystem.DEVICE_OUT_BLE_HEADSET);
         }
 
         // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
@@ -674,8 +708,7 @@
             passedIndex = 4;
         }
         verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
-                STREAM_MUSIC, passedIndex,
-                AudioSystem.DEVICE_OUT_BLE_HEADSET);
+                STREAM_MUSIC, passedIndex, false, AudioSystem.DEVICE_OUT_BLE_HEADSET);
     }
 
     // ---------------- DeviceVolumeBehaviorTest ----------------
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index eb9cce0..d1f6c2f 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -69,7 +69,6 @@
 import com.android.internal.R;
 import com.android.internal.pm.parsing.PackageParser2;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.integrity.engine.RuleEvaluationEngine;
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.pm.parsing.TestPackageParser2;
 import com.android.server.testutils.TestUtils;
@@ -138,7 +137,6 @@
     @Mock PlatformCompat mPlatformCompat;
     @Mock Context mMockContext;
     @Mock Resources mMockResources;
-    @Mock RuleEvaluationEngine mRuleEvaluationEngine;
     @Mock IntegrityFileManager mIntegrityFileManager;
     @Mock Handler mHandler;
 
@@ -176,7 +174,6 @@
                         mMockContext,
                         mPackageManagerInternal,
                         mParserSupplier,
-                        mRuleEvaluationEngine,
                         mIntegrityFileManager,
                         mHandler);
 
@@ -307,91 +304,6 @@
     }
 
     @Test
-    public void handleBroadcast_correctArgs() throws Exception {
-        allowlistUsAsRuleProvider();
-        makeUsSystemApp();
-        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext)
-                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        Intent intent = makeVerificationIntent();
-        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
-
-        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
-        runJobInHandler();
-
-        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
-                ArgumentCaptor.forClass(AppInstallMetadata.class);
-        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
-        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
-        assertEquals(PACKAGE_NAME, appInstallMetadata.getPackageName());
-        assertThat(appInstallMetadata.getAppCertificates()).containsExactly(APP_CERT);
-        assertEquals(INSTALLER_SHA256, appInstallMetadata.getInstallerName());
-        // we cannot check installer cert because it seems to be device specific.
-        assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
-        assertFalse(appInstallMetadata.isPreInstalled());
-        // Asserting source stamp not present.
-        assertFalse(appInstallMetadata.isStampPresent());
-        assertFalse(appInstallMetadata.isStampVerified());
-        assertFalse(appInstallMetadata.isStampTrusted());
-        assertNull(appInstallMetadata.getStampCertificateHash());
-        // These are hardcoded in the test apk android manifest
-        Map<String, String> allowedInstallers =
-                appInstallMetadata.getAllowedInstallersAndCertificates();
-        assertEquals(2, allowedInstallers.size());
-        assertEquals(PLAY_STORE_CERT, allowedInstallers.get(PLAY_STORE_PKG));
-        assertEquals(INSTALLER_CERTIFICATE_NOT_EVALUATED, allowedInstallers.get(ADB_INSTALLER));
-    }
-
-    @Test
-    public void handleBroadcast_correctArgs_multipleCerts() throws Exception {
-        allowlistUsAsRuleProvider();
-        makeUsSystemApp();
-        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext)
-                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        Intent intent = makeVerificationIntent();
-        intent.setDataAndType(Uri.fromFile(mTestApkTwoCerts), PACKAGE_MIME_TYPE);
-        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
-
-        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
-        runJobInHandler();
-
-        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
-                ArgumentCaptor.forClass(AppInstallMetadata.class);
-        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
-        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
-        assertThat(appInstallMetadata.getAppCertificates())
-                .containsExactly(DUMMY_APP_TWO_CERTS_CERT_1, DUMMY_APP_TWO_CERTS_CERT_2);
-    }
-
-    @Test
-    public void handleBroadcast_correctArgs_sourceStamp() throws Exception {
-        allowlistUsAsRuleProvider();
-        makeUsSystemApp();
-        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext)
-                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        Intent intent = makeVerificationIntent();
-        intent.setDataAndType(Uri.fromFile(mTestApkSourceStamp), PACKAGE_MIME_TYPE);
-        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
-
-        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
-        runJobInHandler();
-
-        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
-                ArgumentCaptor.forClass(AppInstallMetadata.class);
-        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
-        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
-        assertTrue(appInstallMetadata.isStampPresent());
-        assertTrue(appInstallMetadata.isStampVerified());
-        assertTrue(appInstallMetadata.isStampTrusted());
-        assertEquals(SOURCE_STAMP_CERTIFICATE_HASH, appInstallMetadata.getStampCertificateHash());
-    }
-
-    @Test
     public void handleBroadcast_allow() throws Exception {
         allowlistUsAsRuleProvider();
         makeUsSystemApp();
@@ -400,7 +312,6 @@
         verify(mMockContext)
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent();
-        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
@@ -411,32 +322,6 @@
     }
 
     @Test
-    public void handleBroadcast_reject() throws Exception {
-        allowlistUsAsRuleProvider();
-        makeUsSystemApp();
-        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext)
-                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        when(mRuleEvaluationEngine.evaluate(any()))
-                .thenReturn(
-                        IntegrityCheckResult.deny(
-                                Arrays.asList(
-                                        new Rule(
-                                                new AtomicFormula.BooleanAtomicFormula(
-                                                        AtomicFormula.PRE_INSTALLED, false),
-                                                Rule.DENY))));
-        Intent intent = makeVerificationIntent();
-
-        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
-        runJobInHandler();
-
-        verify(mPackageManagerInternal)
-                .setIntegrityVerificationResult(
-                        1, PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
-    }
-
-    @Test
     public void handleBroadcast_notInitialized() throws Exception {
         allowlistUsAsRuleProvider();
         makeUsSystemApp();
@@ -446,7 +331,6 @@
         verify(mMockContext)
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent();
-        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
@@ -467,8 +351,6 @@
         verify(mMockContext, atLeastOnce())
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent(TEST_FRAMEWORK_PACKAGE);
-        when(mRuleEvaluationEngine.evaluate(any()))
-                .thenReturn(IntegrityCheckResult.deny(/* rule= */ null));
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
deleted file mode 100644
index e1ee9c3..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.engine;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
-
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.Rule;
-
-import com.android.server.integrity.IntegrityFileManager;
-import com.android.server.integrity.model.IntegrityCheckResult;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-@RunWith(JUnit4.class)
-public class RuleEvaluationEngineTest {
-
-    private static final String INSTALLER_1 = "installer1";
-    private static final String INSTALLER_1_CERT = "installer1_cert";
-    private static final String INSTALLER_2 = "installer2";
-    private static final String INSTALLER_2_CERT = "installer2_cert";
-
-    private static final String RANDOM_INSTALLER = "random";
-    private static final String RANDOM_INSTALLER_CERT = "random_cert";
-
-    @Mock
-    private IntegrityFileManager mIntegrityFileManager;
-
-    private RuleEvaluationEngine mEngine;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        mEngine = new RuleEvaluationEngine(mIntegrityFileManager);
-
-        when(mIntegrityFileManager.readRules(any())).thenReturn(Collections.singletonList(new Rule(
-                IntegrityFormula.Installer.notAllowedByManifest(), Rule.DENY)));
-
-        when(mIntegrityFileManager.initialized()).thenReturn(true);
-    }
-
-    @Test
-    public void testAllowedInstallers_empty() {
-        AppInstallMetadata appInstallMetadata1 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .build();
-        AppInstallMetadata appInstallMetadata2 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_2)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
-                        .build();
-        AppInstallMetadata appInstallMetadata3 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(RANDOM_INSTALLER)
-                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
-                        .build();
-
-        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-    }
-
-    @Test
-    public void testAllowedInstallers_oneElement() {
-        Map<String, String> allowedInstallers =
-                Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT);
-
-        AppInstallMetadata appInstallMetadata1 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata2 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(RANDOM_INSTALLER)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata3 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata4 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-    }
-
-    @Test
-    public void testAllowedInstallers_multipleElement() {
-        Map<String, String> allowedInstallers = new HashMap<>(2);
-        allowedInstallers.put(INSTALLER_1, INSTALLER_1_CERT);
-        allowedInstallers.put(INSTALLER_2, INSTALLER_2_CERT);
-
-        AppInstallMetadata appInstallMetadata1 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata2 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_2)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata3 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata4 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_2)
-                        .setAllowedInstallersAndCert(allowedInstallers)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-    }
-
-    /** Returns a builder with all fields filled with some placeholder data. */
-    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
-        return new AppInstallMetadata.Builder()
-                .setPackageName("abc")
-                .setAppCertificates(Collections.singletonList("abc"))
-                .setAppCertificateLineage(Collections.singletonList("abc"))
-                .setInstallerCertificates(Collections.singletonList("abc"))
-                .setInstallerName("abc")
-                .setVersionCode(-1)
-                .setIsPreInstalled(true);
-    }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index c247c08..3b0cb4a 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -68,6 +68,7 @@
 
 import android.Manifest;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.Flags;
 import android.app.IOnProjectionStateChangedListener;
@@ -247,6 +248,8 @@
         mInjector = spy(new TestInjector());
         mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
                 mTwilightManager, mInjector);
+        // Initialize the current user.
+        mUiManagerService.setCurrentUser(ActivityManager.getCurrentUser());
         try {
             mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         } catch (SecurityException e) {/* ignore for permission denial */}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java b/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java
index 4af96ef..05210ac 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java
@@ -19,13 +19,25 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.app.Application;
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
@@ -35,16 +47,24 @@
 import com.android.server.pm.PackageManagerService;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.List;
 
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 @RunWithLooper
 public class EventConditionProviderTest extends UiServiceTestCase {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
-    EventConditionProvider mService;
+    private EventConditionProvider mService;
+    @Mock private UserManager mUserManager;
 
     @Before
     public void setUp() throws Exception {
@@ -65,6 +85,18 @@
         service.onCreate();
         service.onBind(startIntent);
         mService = spy(service);
+        mService.mContext = this.getContext();
+
+        mContext.addMockSystemService(UserManager.class, mUserManager);
+        when(mUserManager.getProfiles(eq(mUserId))).thenReturn(
+                List.of(new UserInfo(mUserId, "mUserId", 0)));
+
+        doAnswer((Answer<Context>) invocationOnMock -> {
+            Context mockUserContext = mock(Context.class);
+            UserHandle userHandle = invocationOnMock.getArgument(2);
+            when(mockUserContext.getUserId()).thenReturn(userHandle.getIdentifier());
+            return mockUserContext;
+        }).when(mContext).createPackageContextAsUser(any(), anyInt(), any());
     }
 
     @Test
@@ -78,4 +110,52 @@
         PendingIntent pi = mService.getPendingIntent(1000);
         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, pi.getIntent().getPackage());
     }
+
+    @Test
+    @DisableFlags(android.app.Flags.FLAG_MODES_HSUM)
+    public void onBootComplete_flagOff_loadsTrackers() {
+        when(mUserManager.getUserProfiles()).thenReturn(List.of(UserHandle.of(mUserId)));
+
+        mService.onBootComplete();
+
+        assertThat(mService.getTrackers().size()).isEqualTo(1);
+        assertThat(mService.getTrackers().keyAt(0)).isEqualTo(mUserId);
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_MODES_HSUM)
+    public void onBootComplete_waitsForUserSwitched() {
+        mService.onBootComplete();
+        assertThat(mService.getTrackers().size()).isEqualTo(0);
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_MODES_HSUM)
+    public void onUserSwitched_reloadsTrackers() {
+        UserHandle someUser = UserHandle.of(42);
+        when(mUserManager.getProfiles(eq(42))).thenReturn(List.of(new UserInfo(42, "user 42", 0)));
+
+        mService.onUserSwitched(someUser);
+
+        assertThat(mService.getTrackers().size()).isEqualTo(1);
+        assertThat(mService.getTrackers().keyAt(0)).isEqualTo(42);
+        assertThat(mService.getTrackers().valueAt(0).getUserId()).isEqualTo(42);
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_MODES_HSUM)
+    public void onUserSwitched_reloadsTrackersIncludingProfiles() {
+        UserHandle anotherUser = UserHandle.of(42);
+        when(mUserManager.getProfiles(eq(42))).thenReturn(List.of(
+                new UserInfo(42, "user 42", 0),
+                new UserInfo(43, "profile 43", 0)));
+
+        mService.onUserSwitched(anotherUser);
+
+        assertThat(mService.getTrackers().size()).isEqualTo(2);
+        assertThat(mService.getTrackers().keyAt(0)).isEqualTo(42);
+        assertThat(mService.getTrackers().valueAt(0).getUserId()).isEqualTo(42);
+        assertThat(mService.getTrackers().keyAt(1)).isEqualTo(43);
+        assertThat(mService.getTrackers().valueAt(1).getUserId()).isEqualTo(43);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index eef3b25..0f7de7d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -16,6 +16,9 @@
 package com.android.server.notification;
 
 import static android.os.UserHandle.USER_ALL;
+import static android.service.notification.Adjustment.KEY_IMPORTANCE;
+
+import static com.android.server.notification.NotificationManagerService.DEFAULT_ALLOWED_ADJUSTMENTS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -631,4 +634,50 @@
 
         assertThat(mAssistants.getUnsupportedAdjustments(userId).size()).isEqualTo(0);
     }
+
+    @Test
+    @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testDisallowAdjustmentType() {
+        mAssistants.disallowAdjustmentType(Adjustment.KEY_RANKING_SCORE);
+        assertThat(mAssistants.getAllowedAssistantAdjustments())
+                .doesNotContain(Adjustment.KEY_RANKING_SCORE);
+        assertThat(mAssistants.getAllowedAssistantAdjustments()).contains(Adjustment.KEY_TYPE);
+    }
+
+    @Test
+    @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testAllowAdjustmentType() {
+        mAssistants.disallowAdjustmentType(Adjustment.KEY_RANKING_SCORE);
+        assertThat(mAssistants.getAllowedAssistantAdjustments())
+                .doesNotContain(Adjustment.KEY_RANKING_SCORE);
+        mAssistants.allowAdjustmentType(Adjustment.KEY_RANKING_SCORE);
+        assertThat(mAssistants.getAllowedAssistantAdjustments())
+                .contains(Adjustment.KEY_RANKING_SCORE);
+    }
+
+    @Test
+    @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testDisallowAdjustmentType_readWriteXml_entries() throws Exception {
+        int userId = ActivityManager.getCurrentUser();
+
+        mAssistants.loadDefaultsFromConfig(true);
+        mAssistants.disallowAdjustmentType(KEY_IMPORTANCE);
+
+        writeXmlAndReload(USER_ALL);
+
+        assertThat(mAssistants.getAllowedAssistantAdjustments()).contains(
+                Adjustment.KEY_NOT_CONVERSATION);
+        assertThat(mAssistants.getAllowedAssistantAdjustments()).doesNotContain(
+                KEY_IMPORTANCE);
+    }
+
+    @Test
+    public void testDefaultAllowedAdjustments_readWriteXml_entries() throws Exception {
+        mAssistants.loadDefaultsFromConfig(true);
+
+        writeXmlAndReload(USER_ALL);
+
+        assertThat(mAssistants.getAllowedAssistantAdjustments())
+                .containsExactlyElementsIn(DEFAULT_ALLOWED_ADJUSTMENTS);
+    }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 1349ee0..e845d80 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -201,6 +201,7 @@
 import android.app.RemoteInputHistoryItem;
 import android.app.StatsManager;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.app.backup.BackupRestoreEventLogger;
 import android.app.job.JobScheduler;
 import android.app.role.RoleManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -4837,7 +4838,7 @@
                 null, mPkg, Process.myUserHandle());
 
         verify(mPreferencesHelper, times(1)).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4855,7 +4856,7 @@
         }
 
         verify(mPreferencesHelper, never()).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4870,7 +4871,7 @@
                 null, mPkg, Process.myUserHandle());
 
         verify(mPreferencesHelper, times(1)).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4890,7 +4891,7 @@
         }
 
         verify(mPreferencesHelper, never()).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4912,7 +4913,7 @@
         }
 
         verify(mPreferencesHelper, never()).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -6340,7 +6341,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
                 false,
-                UserHandle.USER_ALL);
+                UserHandle.USER_ALL, null);
         verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
         verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
         verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
@@ -6360,7 +6361,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
                 false,
-                UserHandle.USER_ALL);
+                UserHandle.USER_ALL, null);
         verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong());
     }
 
@@ -6372,7 +6373,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
                 false,
-                UserHandle.USER_ALL);
+                UserHandle.USER_ALL, null);
         verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt());
         verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt());
         verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt());
@@ -6404,7 +6405,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
-                10);
+                10, null);
         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
@@ -6430,7 +6431,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
-                10);
+                10, null);
         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
@@ -6458,7 +6459,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
-                10);
+                10, null);
         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
@@ -6485,7 +6486,7 @@
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
-                10);
+                10, null);
         verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10));
         verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10));
         verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10));
@@ -17061,4 +17062,20 @@
         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
                 FLAG_PROMOTED_ONGOING)).isFalse();
     }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testAppCannotUseReservedBundleChannels() throws Exception {
+        mBinderService.getBubblePreferenceForPackage(mPkg, mUid);
+        NotificationChannel news = mBinderService.getNotificationChannel(
+                mPkg, mContext.getUserId(), mPkg, NEWS_ID);
+        assertThat(news).isNotNull();
+
+        NotificationRecord nr = generateNotificationRecord(news);
+        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        assertThat(mService.mNotificationList).isEmpty();
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 50a5f65..4391152 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -546,7 +546,8 @@
     }
 
     @Test
-    @EnableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_VIBRATION_IN_SOUND_URI)
+    @EnableFlags(com.android.server.notification.Flags
+            .FLAG_NOTIFICATION_VIBRATION_IN_SOUND_URI_FOR_CHANNEL)
     public void testVibration_customVibrationForSound_withVibrationUri() throws IOException {
         defaultChannel.enableVibration(true);
         VibrationInfo vibration = getTestingVibration(mVibrator);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 404ede6..b92bdb5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2547,7 +2547,7 @@
 
         // Returns only non-deleted channels
         List<NotificationChannel> channels =
-                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList();
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true).getList();
         // Default channel + non-deleted channel + system defaults
         assertEquals(notificationClassification() ? 6 : 2, channels.size());
         for (NotificationChannel nc : channels) {
@@ -2557,7 +2557,7 @@
         }
 
         // Returns deleted channels too
-        channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList();
+        channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true, true).getList();
         // Includes system channel(s)
         assertEquals(notificationClassification() ? 7 : 3, channels.size());
         for (NotificationChannel nc : channels) {
@@ -3199,7 +3199,8 @@
         mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1);
 
         // Only default channel remains
-        assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList().size());
+        assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true, true)
+                .getList().size());
     }
 
     @Test
@@ -3315,12 +3316,12 @@
         // user 0 records remain
         for (int i = 0; i < user0Uids.length; i++) {
             assertEquals(notificationClassification() ? 5 : 1,
-                    mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false)
+                    mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false, true)
                             .getList().size());
         }
         // user 1 records are gone
         for (int i = 0; i < user1Uids.length; i++) {
-            assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false)
+            assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false, true)
                     .getList().size());
         }
     }
@@ -3337,7 +3338,7 @@
                 new int[]{UID_N_MR1}));
 
         assertEquals(0, mHelper.getNotificationChannels(
-                PKG_N_MR1, UID_N_MR1, true).getList().size());
+                PKG_N_MR1, UID_N_MR1, true, true).getList().size());
 
         // Not deleted
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
@@ -3346,7 +3347,8 @@
         assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM,
                 new String[]{PKG_N_MR1}, new int[]{UID_N_MR1}));
         assertEquals(notificationClassification() ? 6 : 2,
-                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true)
+                        .getList().size());
     }
 
     @Test
@@ -3405,7 +3407,7 @@
         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
-        assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size());
         assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size());
 
         NotificationChannel channel = getChannel();
@@ -3419,7 +3421,8 @@
     public void testRecordDefaults() throws Exception {
         assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
         assertEquals(notificationClassification() ? 5 : 1,
-                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true)
+                        .getList().size());
     }
 
     @Test
@@ -6363,6 +6366,15 @@
 
     @Test
     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testGetNotificationChannels_omitBundleChannels() {
+        // do something that triggers settings creation for an app
+        mHelper.setShowBadge(PKG_O, UID_O, true);
+
+        assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, false).getList()).isEmpty();
+    }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
     public void testNotificationBundles() {
         // do something that triggers settings creation for an app
         mHelper.setShowBadge(PKG_O, UID_O, true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d0080d2..d5f86b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1261,6 +1261,33 @@
     }
 
     @Test
+    public void testLaunchAdjacentDisabled() {
+        final ActivityStarter starter =
+                prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetRootTask */);
+        final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        final ActivityRecord[] outActivity = new ActivityRecord[1];
+
+        // Activity must not land on split-screen task if currently not in split-screen mode.
+        starter.setActivityOptions(options.toBundle())
+                .setReason("testLaunchAdjacentDisabled")
+                .setOutActivity(outActivity).execute();
+        assertThat(outActivity[0].inMultiWindowMode()).isFalse();
+
+        // Move activity to split-screen-primary task and make sure it has the focus.
+        TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayContent());
+        top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
+        top.getRootTask().moveToFront("testLaunchAdjacentDisabled");
+        top.getRootTask().setLaunchAdjacentDisabled(true);
+
+        // Ensure activity does not launch into split-screen-secondary when launch adjacent is
+        // disabled
+        startActivityInner(starter, outActivity[0], top, options, null /* inTask */,
+                null /* taskFragment*/);
+        assertThat(outActivity[0].isDescendantOf(splitOrg.mSecondary)).isFalse();
+    }
+
+    @Test
     public void testTransientLaunchWithKeyguard() {
         final ActivityStarter starter = prepareStarter(0 /* flags */);
         final ActivityRecord target = new ActivityBuilder(mAtm).setCreateTask(true).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
index 3910904..7509681 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java
@@ -683,6 +683,41 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES)
+    public void testRealCaller_sawPermission() {
+        int callingUid = REGULAR_UID_1;
+        int callingPid = REGULAR_PID_1;
+        final String callingPackage = REGULAR_PACKAGE_1;
+        int realCallingUid = REGULAR_UID_2;
+        int realCallingPid = REGULAR_PID_2;
+
+        // setup state
+        when(mService.hasSystemAlertWindowPermission(eq(realCallingUid), eq(realCallingPid),
+                any())).thenReturn(true);
+
+        // prepare call
+        PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
+        BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE;
+        Intent intent = TEST_INTENT;
+        ActivityOptions checkedOptions =
+                mCheckedOptions.setPendingIntentBackgroundActivityStartMode(
+                        MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+        BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid,
+                callingPid, callingPackage, realCallingUid, realCallingPid, null,
+                originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent,
+                checkedOptions);
+
+        // call
+        BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller(
+                balState);
+        balState.setResultForCaller(callerVerdict);
+
+        // assertions
+        assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo(
+                BAL_ALLOW_SAW_PERMISSION);
+    }
+
+    @Test
     public void testCaller_isRecents() {
         int callingUid = REGULAR_UID_1;
         int callingPid = REGULAR_PID_1;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 72f4fa91..c30f70e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -183,15 +183,32 @@
         DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags);
     }
 
-    private void setUpApp(DisplayContent display) {
-        mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build();
-        mActivity = mTask.getTopNonFinishingActivity();
-        doReturn(false).when(mActivity).isImmersiveMode(any());
+    private ActivityRecord setUpApp(DisplayContent display) {
+        return setUpApp(display, null /* appBuilder */);
     }
 
-    private void setUpDisplaySizeWithApp(int dw, int dh) {
+    private ActivityRecord setUpApp(DisplayContent display, ActivityBuilder appBuilder) {
+        // Use the real package name (com.android.frameworks.wmtests) so that
+        // EnableCompatChanges/DisableCompatChanges can take effect.
+        // Otherwise the fake WindowTestsBase.DEFAULT_COMPONENT_PACKAGE_NAME will make
+        // PlatformCompat#isChangeEnabledByPackageName always return default value.
+        final ComponentName componentName = ComponentName.createRelative(
+                mContext, SizeCompatTests.class.getName());
+        mTask = new TaskBuilder(mSupervisor).setDisplay(display).setComponent(componentName)
+                .build();
+        final ActivityBuilder builder = appBuilder != null ? appBuilder : new ActivityBuilder(mAtm);
+        mActivity = builder.setTask(mTask).setComponent(componentName).build();
+        doReturn(false).when(mActivity).isImmersiveMode(any());
+        return mActivity;
+    }
+
+    private ActivityRecord setUpDisplaySizeWithApp(int dw, int dh) {
+        return setUpDisplaySizeWithApp(dw, dh, null /* appBuilder */);
+    }
+
+    private ActivityRecord setUpDisplaySizeWithApp(int dw, int dh, ActivityBuilder appBuilder) {
         final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mAtm, dw, dh);
-        setUpApp(builder.build());
+        return setUpApp(builder.build(), appBuilder);
     }
 
     @Test
@@ -352,15 +369,13 @@
                 .setCanRotate(false)
                 .setNotch(cutoutHeight)
                 .build();
-        setUpApp(display);
         display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         mWm.mAppCompatConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
         mWm.mAppCompatConfiguration.setIsVerticalReachabilityEnabled(true);
 
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
-                .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE)
-                .build();
+                .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE));
 
         doReturn(true).when(activity).isImmersiveMode(any());
         addWindowToActivity(activity);
@@ -424,17 +439,16 @@
     @Test
     @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
     public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
-        final int notchHeight = 100;
-        setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build());
-
-        final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds();
         final float aspectRatio = 1.2f;
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
+        final ActivityBuilder activityBuilder = new ActivityBuilder(mAtm)
                 .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
                 .setMinAspectRatio(aspectRatio)
                 .setMaxAspectRatio(aspectRatio)
-                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
-                .build();
+                .setResizeMode(RESIZE_MODE_UNRESIZEABLE);
+        final int notchHeight = 100;
+        final ActivityRecord activity = setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800)
+                .setNotch(notchHeight).build(), activityBuilder);
+        final Rect displayBounds = activity.mDisplayContent.getWindowConfiguration().getBounds();
         final Rect appBounds = activity.getWindowConfiguration().getAppBounds();
 
         // The parent configuration doesn't change since the first resolved configuration, so the
@@ -1327,12 +1341,8 @@
     public void testOverrideMinAspectRatioSmall_overridden() {
         final int dh = 1200;
         final int dw = 1000;
-        setUpDisplaySizeWithApp(dw, dh);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(dw, dh, new ActivityBuilder(mAtm)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         final Rect bounds = activity.getBounds();
         assertEquals(dh, bounds.height());
@@ -1346,13 +1356,9 @@
     public void testOverrideMinAspectRatioSmall_notOverridden() {
         final int dh = 1200;
         final int dw = 1000;
-        setUpDisplaySizeWithApp(dw, dh);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(dw, dh, new ActivityBuilder(mAtm)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE));
 
         // Activity's requested aspect ratio is larger than OVERRIDE_MIN_ASPECT_RATIO_SMALL,
         // so OVERRIDE_MIN_ASPECT_RATIO_SMALL is ignored.
@@ -1366,12 +1372,8 @@
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
     public void testOverrideMinAspectRatioMedium() {
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         // The per-package override forces the activity into a 3:2 aspect ratio
         assertEquals(1200, activity.getBounds().height());
@@ -1388,13 +1390,8 @@
         final int notchHeight = 200;
         final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1400, dh)
                 .setNotch(notchHeight).setSystemDecorations(true).build();
-        mTask = new TaskBuilder(mSupervisor).setDisplay(display).build();
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .setMinAspectRatio(2f)
-                .build();
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).setMinAspectRatio(2f));
 
         // The per-package override should have no effect, because the manifest aspect ratio is
         // larger (2:1)
@@ -1411,13 +1408,9 @@
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
     public void testOverrideMinAspectRatioLargerThanManifest() {
-        setUpDisplaySizeWithApp(1400, 1600);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .setMinAspectRatio(1.1f)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1400, 1600,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                        .setMinAspectRatio(1.1f));
 
         // The per-package override should have no effect, because the manifest aspect ratio is
         // larger (2:1)
@@ -1430,12 +1423,8 @@
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
     public void testOverrideMinAspectRatioLarge() {
-        setUpDisplaySizeWithApp(1500, 1600);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1500, 1600,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         // The per-package override forces the activity into a 16:9 aspect ratio
         assertEquals(1600, activity.getBounds().height());
@@ -1449,13 +1438,8 @@
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
     public void testOverrideMinAspectRatio_Both() {
         // If multiple override aspect ratios are set, we should use the largest one
-
-        setUpDisplaySizeWithApp(1400, 1600);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1400, 1600,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         // The per-package override forces the activity into a 16:9 aspect ratio
         assertEquals(1600, activity.getBounds().height());
@@ -1470,11 +1454,7 @@
     public void testOverrideMinAspectRatioScreenOrientationNotSetThenChangedToPortrait() {
         // In this test, the activity's orientation isn't fixed to portrait, therefore the override
         // isn't applied.
-
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200);
 
         // The per-package override should have no effect
         assertEquals(1200, activity.getBounds().height());
@@ -1497,13 +1477,8 @@
     public void testOverrideMinAspectRatioScreenOrientationLandscapeThenChangedToPortrait() {
         // In this test, the activity's orientation isn't fixed to portrait, therefore the override
         // isn't applied.
-
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE));
 
         // The per-package override should have no effect
         assertEquals(1200, activity.getBounds().height());
@@ -1524,12 +1499,8 @@
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
     public void testOverrideMinAspectRatioScreenOrientationPortraitThenChangedToUnspecified() {
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         // The per-package override forces the activity into a 3:2 aspect ratio
         assertEquals(1200, activity.getBounds().height());
@@ -1550,10 +1521,7 @@
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
     @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
     public void testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationNotSet() {
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200);
 
         // The per-package override forces the activity into a 3:2 aspect ratio
         assertEquals(1200, activity.getBounds().height());
@@ -1568,13 +1536,8 @@
     public void testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationLandscape() {
         // In this test, the activity's orientation isn't fixed to portrait, therefore the override
         // isn't applied.
-
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE));
 
         // The per-package override forces the activity into a 3:2 aspect ratio
         assertEquals(1000 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
@@ -1588,12 +1551,8 @@
         // In this test, only OVERRIDE_MIN_ASPECT_RATIO_1_5 is set, which has no effect without
         // OVERRIDE_MIN_ASPECT_RATIO being also set.
 
-        setUpDisplaySizeWithApp(1000, 1200);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(1000, 1200,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE));
 
         // The per-package override should have no effect
         assertEquals(1200, activity.getBounds().height());
@@ -1604,12 +1563,8 @@
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
     public void testOverrideMinAspectRatioLargeForResizableAppInSplitScreen() {
-        setUpDisplaySizeWithApp(/* dw= */ 1000, /* dh= */ 2800);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(/* dw= */ 1000, /* dh= */ 2800,
+                new ActivityBuilder(mAtm).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         final TestSplitOrganizer organizer =
                 new TestSplitOrganizer(mAtm, activity.getDisplayContent());
@@ -2462,10 +2417,8 @@
     public void testOverrideSplitScreenAspectRatioForUnresizablePortraitApps() {
         final int displayWidth = 1400;
         final int displayHeight = 1600;
-        setUpDisplaySizeWithApp(displayWidth, displayHeight);
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setMinAspectRatio(1.1f)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(displayWidth, displayHeight,
+                new ActivityBuilder(mAtm).setMinAspectRatio(1.1f));
         // Setup Letterbox Configuration
         activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         activity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
@@ -2483,10 +2436,8 @@
     public void testOverrideSplitScreenAspectRatioForUnresizablePortraitAppsFromLandscape() {
         final int displayWidth = 1600;
         final int displayHeight = 1400;
-        setUpDisplaySizeWithApp(displayWidth, displayHeight);
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setMinAspectRatio(1.1f)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(displayWidth, displayHeight,
+                new ActivityBuilder(mAtm).setMinAspectRatio(1.1f));
         // Setup Letterbox Configuration
         activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         activity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
@@ -2505,10 +2456,8 @@
     public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeApps() {
         final int displayWidth = 1400;
         final int displayHeight = 1600;
-        setUpDisplaySizeWithApp(displayWidth, displayHeight);
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setMinAspectRatio(1.1f)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(displayWidth, displayHeight,
+                new ActivityBuilder(mAtm).setMinAspectRatio(1.1f));
         // Setup Letterbox Configuration
         activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         activity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
@@ -2527,10 +2476,8 @@
     public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeAppsFromLandscape() {
         final int displayWidth = 1600;
         final int displayHeight = 1400;
-        setUpDisplaySizeWithApp(displayWidth, displayHeight);
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setMinAspectRatio(1.1f)
-                .build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(displayWidth, displayHeight,
+                new ActivityBuilder(mAtm).setMinAspectRatio(1.1f));
         // Setup Letterbox Configuration
         activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         activity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
@@ -2549,8 +2496,7 @@
         mAtm.mDevEnableNonResizableMultiWindow = true;
         final int screenWidth = 1800;
         final int screenHeight = 1000;
-        setUpDisplaySizeWithApp(screenWidth, screenHeight);
-        final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(screenWidth, screenHeight);
 
         activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         // Simulate real display with top insets.
@@ -2585,8 +2531,7 @@
         mAtm.mDevEnableNonResizableMultiWindow = true;
         final int screenWidth = 1000;
         final int screenHeight = 1800;
-        setUpDisplaySizeWithApp(screenWidth, screenHeight);
-        final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+        final ActivityRecord activity = setUpDisplaySizeWithApp(screenWidth, screenHeight);
 
         activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         // Simulate real display with top insets.
@@ -2616,18 +2561,18 @@
 
     @Test
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN})
     public void testOverrideMinAspectRatioExcludePortraitFullscreen() {
-        setUpDisplaySizeWithApp(2600, 1600);
-        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
-        mActivity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
-
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+        resizeDisplay(mDisplayContent, 2600, 1600);
+        mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mWm.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
 
         // Non-resizable portrait activity
-        prepareUnresizable(activity, 0f, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        final ActivityRecord activity = setUpApp(mDisplayContent, new ActivityBuilder(mAtm)
+                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         // At first, OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply, because the
         // display is in landscape
@@ -2645,16 +2590,16 @@
 
     @Test
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN})
     public void testOverrideMinAspectRatioExcludePortraitFullscreenNotApplied() {
         // In this test, the activity is not in fullscreen, so the override is not applied
-        setUpDisplaySizeWithApp(2600, 1600);
-        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
-        mActivity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
+        resizeDisplay(mDisplayContent, 2600, 1600);
+        mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mWm.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
 
-        // Create a size compat activity on the same task.
-        final ActivityRecord activity = getActivityBuilderOnSameTask().build();
+        final ActivityRecord activity = setUpApp(mDisplayContent);
 
         final TestSplitOrganizer organizer =
                 new TestSplitOrganizer(mAtm, activity.getDisplayContent());
@@ -2983,6 +2928,7 @@
     }
 
     @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION})
     public void testDisplayIgnoreOrientationRequest_orientationChangedToUnspecified() {
         // Set up a display in landscape and ignoring orientation request.
         setUpDisplaySizeWithApp(2800, 1400);
@@ -3437,6 +3383,7 @@
     }
 
     @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION})
     public void testSupportsNonResizableInSplitScreen_letterboxForAspectRatioRestriction() {
         // Support non resizable in multi window
         mAtm.mDevEnableNonResizableMultiWindow = true;
@@ -4050,9 +3997,9 @@
     @Test
     @EnableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION})
     public void testPortraitCloseToSquareDisplayWithTaskbar_insetsOverridden_notLetterboxed() {
+        final DisplayContent display = mDisplayContent;
         // Set up portrait close to square display.
-        setUpDisplaySizeWithApp(2200, 2280);
-        final DisplayContent display = mActivity.mDisplayContent;
+        resizeDisplay(display, 2200, 2280);
         display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         // Simulate insets, final app bounds are (0, 0, 2200, 2130) - landscape.
         final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
@@ -4067,9 +4014,8 @@
             display.sendNewConfiguration();
         }
 
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         // Activity should not be letterboxed and should have portrait app bounds even though
         // orientation is not respected with insets as insets have been decoupled.
@@ -4085,9 +4031,9 @@
     @Test
     @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
     public void testPortraitCloseToSquareDisplayWithTaskbar_letterboxed() {
+        final DisplayContent display = mDisplayContent;
         // Set up portrait close to square display
-        setUpDisplaySizeWithApp(2200, 2280);
-        final DisplayContent display = mActivity.mDisplayContent;
+        resizeDisplay(display, 2200, 2280);
         display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         // Simulate taskbar, final app bounds are (0, 0, 2200, 2130) - landscape
         final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
@@ -4102,9 +4048,8 @@
             display.sendNewConfiguration();
         }
 
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
-                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
-                .build();
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT));
 
         final Rect bounds = activity.getBounds();
         // Activity should be letterboxed and should have portrait app bounds
@@ -4116,9 +4061,9 @@
     @Test
     @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
     public void testFixedAspectRatioAppInPortraitCloseToSquareDisplay_notInSizeCompat() {
-        setUpDisplaySizeWithApp(2200, 2280);
-        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
-        final DisplayContent dc = mActivity.mDisplayContent;
+        final DisplayContent dc = mDisplayContent;
+        resizeDisplay(dc, 2200, 2280);
+        dc.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         // Simulate taskbar, final app bounds are (0, 0, 2200, 2130) - landscape
         final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
                 "navbar");
@@ -4132,11 +4077,10 @@
             dc.sendNewConfiguration();
         }
 
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
+        final ActivityRecord activity = setUpApp(dc, new ActivityBuilder(mAtm)
                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
-                .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE)
-                .build();
+                .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE));
         // To force config to update again but with the same landscape orientation.
         activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
 
@@ -4174,13 +4118,10 @@
                 .setCutout(0, 100, 0, 150)
                 .build();
 
-        setUpApp(display);
-
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                 .setMaxAspectRatio(2.1f)
-                .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
-                .build();
+                .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
 
         // The activity height is 2100 and the display's app bounds height is 2050, so the activity
         // cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display
@@ -4196,13 +4137,10 @@
                 .setCutout(100, 0, 150, 0)
                 .build();
 
-        setUpApp(display);
-
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                 .setMaxAspectRatio(2.1f)
-                .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
-                .build();
+                .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
         // The activity width is 2100 and the display's app bounds width is 2250, so the activity
         // can be aligned inside parentAppBounds
         assertEquals(activity.getBounds(), new Rect(175, 0, 2275, 1000));
@@ -4216,12 +4154,10 @@
                 .setCutout(100, 0, 150, 0)
                 .build();
 
-        setUpApp(display);
-        final ActivityRecord activity = getActivityBuilderOnSameTask()
+        final ActivityRecord activity = setUpApp(display, new ActivityBuilder(mAtm)
                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                 .setMaxAspectRatio(2.1f)
-                .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
-                .build();
+                .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
         // The activity width is 2100 and the display's app bounds width is 2050, so the activity
         // cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display
         assertEquals(activity.getBounds(), display.getBounds());
@@ -4883,7 +4819,7 @@
 
 
     @Test
-    @EnableCompatChanges({ActivityRecord.UNIVERSAL_RESIZABLE_BY_DEFAULT})
+    @EnableCompatChanges({ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT})
     public void testUniversalResizeableByDefault() {
         mSetFlagsRule.enableFlags(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT);
         mDisplayContent.setIgnoreOrientationRequest(false);
@@ -5032,17 +4968,13 @@
      */
     private ActivityRecord buildActivityRecord(boolean supportsSizeChanges, int resizeMode,
             @ScreenOrientation int screenOrientation) {
-        return getActivityBuilderOnSameTask()
+        return getActivityBuilderWithoutTask().setTask(mTask)
                 .setResizeMode(resizeMode)
                 .setSupportsSizeChanges(supportsSizeChanges)
                 .setScreenOrientation(screenOrientation)
                 .build();
     }
 
-    private ActivityBuilder getActivityBuilderOnSameTask() {
-        return getActivityBuilderWithoutTask().setTask(mTask);
-    }
-
     private ActivityBuilder getActivityBuilderWithoutTask() {
         return new ActivityBuilder(mAtm)
                 .setComponent(ComponentName.createRelative(mContext,
diff --git a/services/usb/java/com/android/server/usb/UsbManagerInternal.java b/services/usb/java/com/android/server/usb/UsbManagerInternal.java
index c97df6b..31c5986 100644
--- a/services/usb/java/com/android/server/usb/UsbManagerInternal.java
+++ b/services/usb/java/com/android/server/usb/UsbManagerInternal.java
@@ -34,9 +34,11 @@
 public abstract class UsbManagerInternal {
 
   public static final int OS_USB_DISABLE_REASON_AAPM = 0;
+  public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;
 
   @Retention(RetentionPolicy.SOURCE)
-  @IntDef(value = {OS_USB_DISABLE_REASON_AAPM})
+  @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
+    OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
   public @interface OsUsbDisableReason {
   }
 
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index ba9dff6..ec4f7e1 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -1527,8 +1527,11 @@
             }
             mLockdownModeStatus = lockDownTriggeredByUser;
             for (UsbPort port: mPortManager.getPorts()) {
-                enableUsbData(port.getId(), !lockDownTriggeredByUser, STRONG_AUTH_OPERATION_ID,
-                        new IUsbOperationInternal.Default());
+                enableUsbDataInternal(port.getId(), !lockDownTriggeredByUser,
+                    STRONG_AUTH_OPERATION_ID,
+                    new IUsbOperationInternal.Default(),
+                    UsbManagerInternal.OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
+                    true);
             }
         }
     }
diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java
index e2fb601..ad0d4f4 100644
--- a/telecomm/java/android/telecom/Logging/Session.java
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -16,7 +16,6 @@
 
 package android.telecom.Logging;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -24,8 +23,13 @@
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.telecom.flags.Flags;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Stores information about a thread's point of entry into that should persist until that thread
@@ -55,7 +59,7 @@
      * Initial value of mExecutionEndTimeMs and the final value of {@link #getLocalExecutionTime()}
      * if the Session is canceled.
      */
-    public static final int UNDEFINED = -1;
+    public static final long UNDEFINED = -1;
 
     public static class Info implements Parcelable {
         public final String sessionId;
@@ -129,46 +133,39 @@
         }
     }
 
-    private String mSessionId;
-    private String mShortMethodName;
+    private final String mSessionId;
+    private volatile String mShortMethodName;
     private long mExecutionStartTimeMs;
     private long mExecutionEndTimeMs = UNDEFINED;
-    private Session mParentSession;
-    private ArrayList<Session> mChildSessions;
+    private volatile Session mParentSession;
+    private final ArrayList<Session> mChildSessions = new ArrayList<>(5);
     private boolean mIsCompleted = false;
-    private boolean mIsExternal = false;
-    private int mChildCounter = 0;
+    private final boolean mIsExternal;
+    private final AtomicInteger mChildCounter = new AtomicInteger(0);
     // True if this is a subsession that has been started from the same thread as the parent
     // session. This can happen if Log.startSession(...) is called multiple times on the same
     // thread in the case of one Telecom entry point method calling another entry point method.
     // In this case, we can just make this subsession "invisible," but still keep track of it so
     // that the Log.endSession() calls match up.
-    private boolean mIsStartedFromActiveSession = false;
+    private final boolean mIsStartedFromActiveSession;
     // Optionally provided info about the method/class/component that started the session in order
     // to make Logging easier. This info will be provided in parentheses along with the session.
-    private String mOwnerInfo;
+    private final String mOwnerInfo;
     // Cache Full Method path so that recursive population of the full method path only needs to
     // be calculated once.
-    private String mFullMethodPathCache;
+    private volatile String mFullMethodPathCache;
 
     public Session(String sessionId, String shortMethodName, long startTimeMs,
-            boolean isStartedFromActiveSession, String ownerInfo) {
-        setSessionId(sessionId);
+            boolean isStartedFromActiveSession, boolean isExternal, String ownerInfo) {
+        mSessionId = (sessionId != null) ? sessionId : "???";
         setShortMethodName(shortMethodName);
         mExecutionStartTimeMs = startTimeMs;
         mParentSession = null;
-        mChildSessions = new ArrayList<>(5);
         mIsStartedFromActiveSession = isStartedFromActiveSession;
+        mIsExternal = isExternal;
         mOwnerInfo = ownerInfo;
     }
 
-    public void setSessionId(@NonNull String sessionId) {
-        if (sessionId == null) {
-            mSessionId = "?";
-        }
-        mSessionId = sessionId;
-    }
-
     public String getShortMethodName() {
         return mShortMethodName;
     }
@@ -180,10 +177,6 @@
         mShortMethodName = shortMethodName;
     }
 
-    public void setIsExternal(boolean isExternal) {
-        mIsExternal = isExternal;
-    }
-
     public boolean isExternal() {
         return mIsExternal;
     }
@@ -193,13 +186,15 @@
     }
 
     public void addChild(Session childSession) {
-        if (childSession != null) {
+        if (childSession == null) return;
+        synchronized (mChildSessions) {
             mChildSessions.add(childSession);
         }
     }
 
     public void removeChild(Session child) {
-        if (child != null) {
+        if (child == null) return;
+        synchronized (mChildSessions) {
             mChildSessions.remove(child);
         }
     }
@@ -217,7 +212,9 @@
     }
 
     public ArrayList<Session> getChildSessions() {
-        return mChildSessions;
+        synchronized (mChildSessions) {
+            return new ArrayList<>(mChildSessions);
+        }
     }
 
     public boolean isSessionCompleted() {
@@ -259,17 +256,41 @@
         return mExecutionEndTimeMs - mExecutionStartTimeMs;
     }
 
-    public synchronized String getNextChildId() {
-        return String.valueOf(mChildCounter++);
+    public String getNextChildId() {
+        return String.valueOf(mChildCounter.getAndIncrement());
     }
 
-    // Builds full session id recursively
+    // Builds full session ID, which incliudes the optional external indicators (E),
+    // base session ID, and the optional sub-session IDs (_X): @[E-]...[ID][_X][_Y]...
     private String getFullSessionId() {
-        return getFullSessionId(0);
+        if (!Flags.endSessionImprovements()) return getFullSessionIdRecursive(0);
+        int currParentCount = 0;
+        StringBuilder id = new StringBuilder();
+        Session currSession = this;
+        while (currSession != null) {
+            Session parentSession = currSession.getParentSession();
+            if (parentSession != null) {
+                if (currParentCount >= SESSION_RECURSION_LIMIT) {
+                    id.insert(0, getSessionId());
+                    id.insert(0, TRUNCATE_STRING);
+                    android.util.Slog.w(LOG_TAG, "getFullSessionId: Hit iteration limit!");
+                    return id.toString();
+                }
+                if (Log.VERBOSE) {
+                    id.insert(0, currSession.getSessionId());
+                    id.insert(0, SESSION_SEPARATION_CHAR_CHILD);
+                }
+            } else {
+                id.insert(0, currSession.getSessionId());
+            }
+            currSession = parentSession;
+            currParentCount++;
+        }
+        return id.toString();
     }
 
     // keep track of calls and bail if we hit the recursion limit
-    private String getFullSessionId(int parentCount) {
+    private String getFullSessionIdRecursive(int parentCount) {
         if (parentCount >= SESSION_RECURSION_LIMIT) {
             // Don't use Telecom's Log.w here or it will cause infinite recursion because it will
             // try to add session information to this logging statement, which will cause it to hit
@@ -286,12 +307,12 @@
             return mSessionId;
         } else {
             if (Log.VERBOSE) {
-                return parentSession.getFullSessionId(parentCount + 1)
+                return parentSession.getFullSessionIdRecursive(parentCount + 1)
                         // Append "_X" to subsession to show subsession designation.
                         + SESSION_SEPARATION_CHAR_CHILD + mSessionId;
             } else {
                 // Only worry about the base ID at the top of the tree.
-                return parentSession.getFullSessionId(parentCount + 1);
+                return parentSession.getFullSessionIdRecursive(parentCount + 1);
             }
 
         }
@@ -300,16 +321,18 @@
     private Session getRootSession(String callingMethod) {
         int currParentCount = 0;
         Session topNode = this;
-        while (topNode.getParentSession() != null) {
+        Session parentNode = topNode.getParentSession();
+        while (parentNode != null) {
             if (currParentCount >= SESSION_RECURSION_LIMIT) {
                 // Don't use Telecom's Log.w here or it will cause infinite recursion because it
                 // will try to add session information to this logging statement, which will cause
                 // it to hit this condition again and so on...
-                android.util.Slog.w(LOG_TAG, "getRootSession: Hit recursion limit from "
+                android.util.Slog.w(LOG_TAG, "getRootSession: Hit iteration limit from "
                         + callingMethod);
                 break;
             }
-            topNode = topNode.getParentSession();
+            topNode = parentNode;
+            parentNode = topNode.getParentSession();
             currParentCount++;
         }
         return topNode;
@@ -320,14 +343,40 @@
         return getRootSession("printFullSessionTree").printSessionTree();
     }
 
-    // Recursively move down session tree using DFS, but print out each node when it is reached.
     private String printSessionTree() {
         StringBuilder sb = new StringBuilder();
-        printSessionTree(0, sb, 0);
+        if (!Flags.endSessionImprovements()) {
+            printSessionTreeRecursive(0, sb, 0);
+            return sb.toString();
+        }
+        int depth = 0;
+        ArrayDeque<Session> deque = new ArrayDeque<>();
+        deque.add(this);
+        while (!deque.isEmpty()) {
+            Session node = deque.pollFirst();
+            sb.append("\t".repeat(depth));
+            sb.append(node.toString());
+            sb.append("\n");
+            if (depth >= SESSION_RECURSION_LIMIT) {
+                sb.append(TRUNCATE_STRING);
+                depth -= 1;
+                continue;
+            }
+            List<Session> childSessions = node.getChildSessions().reversed();
+            if (!childSessions.isEmpty()) {
+                depth += 1;
+                for (Session child : childSessions) {
+                    deque.addFirst(child);
+                }
+            } else {
+                depth -= 1;
+            }
+        }
         return sb.toString();
     }
 
-    private void printSessionTree(int tabI, StringBuilder sb, int currChildCount) {
+    // Recursively move down session tree using DFS, but print out each node when it is reached.
+    private void printSessionTreeRecursive(int tabI, StringBuilder sb, int currChildCount) {
         // Prevent infinite recursion.
         if (currChildCount >= SESSION_RECURSION_LIMIT) {
             // Don't use Telecom's Log.w here or it will cause infinite recursion because it will
@@ -343,26 +392,85 @@
             for (int i = 0; i <= tabI; i++) {
                 sb.append("\t");
             }
-            child.printSessionTree(tabI + 1, sb, currChildCount + 1);
+            child.printSessionTreeRecursive(tabI + 1, sb, currChildCount + 1);
         }
     }
 
-    // Recursively concatenate mShortMethodName with the parent Sessions to create full method
-    // path. if truncatePath is set to true, all other external sessions (except for the most
-    // recent) will be truncated to "..."
+    //
+
+    /**
+     * Concatenate the short method name with the parent Sessions to create full method path.
+     * @param truncatePath if truncatePath is set to true, all other external sessions (except for
+     *                     the most recent) will be truncated to "..."
+     * @return The full method path associated with this Session.
+     */
+    @VisibleForTesting
     public String getFullMethodPath(boolean truncatePath) {
         StringBuilder sb = new StringBuilder();
-        getFullMethodPath(sb, truncatePath, 0);
+        if (!Flags.endSessionImprovements()) {
+            getFullMethodPathRecursive(sb, truncatePath, 0);
+            return sb.toString();
+        }
+        // Check to see if the session has been renamed yet. If it has not, then the session
+        // has not been continued.
+        Session parentSession = getParentSession();
+        boolean isSessionStarted = parentSession == null
+                || !getShortMethodName().equals(parentSession.getShortMethodName());
+        int depth = 0;
+        Session currSession = this;
+        while (currSession != null) {
+            String cache = currSession.mFullMethodPathCache;
+            // Return cached value for method path. When returning the truncated path, recalculate
+            // the full path without using the cached value.
+            if (!TextUtils.isEmpty(cache) && !truncatePath) {
+                sb.insert(0, cache);
+                return sb.toString();
+            }
+
+            parentSession = currSession.getParentSession();
+            // Encapsulate the external session's method name so it is obvious what part of the
+            // session is external or truncate it if we do not want the entire history.
+            if (currSession.isExternal()) {
+                if (truncatePath) {
+                    sb.insert(0, TRUNCATE_STRING);
+                } else {
+                    sb.insert(0, ")");
+                    sb.insert(0, currSession.getShortMethodName());
+                    sb.insert(0, "(");
+                }
+            } else {
+                sb.insert(0, currSession.getShortMethodName());
+            }
+            if (parentSession != null) {
+                sb.insert(0, SUBSESSION_SEPARATION_CHAR);
+            }
+
+            if (depth >= SESSION_RECURSION_LIMIT) {
+                // Don't use Telecom's Log.w here or it will cause infinite recursion because it
+                // will try to add session information to this logging statement, which will cause
+                // it to hit this condition again and so on...
+                android.util.Slog.w(LOG_TAG, "getFullMethodPath: Hit iteration limit!");
+                sb.insert(0, TRUNCATE_STRING);
+                return sb.toString();
+            }
+            currSession = parentSession;
+            depth++;
+        }
+        if (isSessionStarted && !truncatePath) {
+            // Cache the full method path for this node so that we do not need to calculate it
+            // again in the future.
+            mFullMethodPathCache = sb.toString();
+        }
         return sb.toString();
     }
 
-    private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath,
+    private synchronized void getFullMethodPathRecursive(StringBuilder sb, boolean truncatePath,
             int parentCount) {
         if (parentCount >= SESSION_RECURSION_LIMIT) {
             // Don't use Telecom's Log.w here or it will cause infinite recursion because it will
             // try to add session information to this logging statement, which will cause it to hit
             // this condition again and so on...
-            android.util.Slog.w(LOG_TAG, "getFullMethodPath: Hit recursion limit!");
+            android.util.Slog.w(LOG_TAG, "getFullMethodPathRecursive: Hit recursion limit!");
             sb.append(TRUNCATE_STRING);
             return;
         }
@@ -378,7 +486,7 @@
             // Check to see if the session has been renamed yet. If it has not, then the session
             // has not been continued.
             isSessionStarted = !mShortMethodName.equals(parentSession.mShortMethodName);
-            parentSession.getFullMethodPath(sb, truncatePath, parentCount + 1);
+            parentSession.getFullMethodPathRecursive(sb, truncatePath, parentCount + 1);
             sb.append(SUBSESSION_SEPARATION_CHAR);
         }
         // Encapsulate the external session's method name so it is obvious what part of the session
@@ -409,14 +517,14 @@
 
     @Override
     public int hashCode() {
-        int result = mSessionId != null ? mSessionId.hashCode() : 0;
-        result = 31 * result + (mShortMethodName != null ? mShortMethodName.hashCode() : 0);
-        result = 31 * result + (int) (mExecutionStartTimeMs ^ (mExecutionStartTimeMs >>> 32));
-        result = 31 * result + (int) (mExecutionEndTimeMs ^ (mExecutionEndTimeMs >>> 32));
+        int result = mSessionId.hashCode();
+        result = 31 * result + mShortMethodName.hashCode();
+        result = 31 * result + Long.hashCode(mExecutionStartTimeMs);
+        result = 31 * result + Long.hashCode(mExecutionEndTimeMs);
         result = 31 * result + (mParentSession != null ? mParentSession.hashCode() : 0);
-        result = 31 * result + (mChildSessions != null ? mChildSessions.hashCode() : 0);
+        result = 31 * result + mChildSessions.hashCode();
         result = 31 * result + (mIsCompleted ? 1 : 0);
-        result = 31 * result + mChildCounter;
+        result = 31 * result + mChildCounter.hashCode();
         result = 31 * result + (mIsStartedFromActiveSession ? 1 : 0);
         result = 31 * result + (mOwnerInfo != null ? mOwnerInfo.hashCode() : 0);
         return result;
@@ -432,23 +540,13 @@
         if (mExecutionStartTimeMs != session.mExecutionStartTimeMs) return false;
         if (mExecutionEndTimeMs != session.mExecutionEndTimeMs) return false;
         if (mIsCompleted != session.mIsCompleted) return false;
-        if (mChildCounter != session.mChildCounter) return false;
+        if (!(mChildCounter.get() == session.mChildCounter.get())) return false;
         if (mIsStartedFromActiveSession != session.mIsStartedFromActiveSession) return false;
-        if (mSessionId != null ?
-                !mSessionId.equals(session.mSessionId) : session.mSessionId != null)
-            return false;
-        if (mShortMethodName != null ? !mShortMethodName.equals(session.mShortMethodName)
-                : session.mShortMethodName != null)
-            return false;
-        if (mParentSession != null ? !mParentSession.equals(session.mParentSession)
-                : session.mParentSession != null)
-            return false;
-        if (mChildSessions != null ? !mChildSessions.equals(session.mChildSessions)
-                : session.mChildSessions != null)
-            return false;
-        return mOwnerInfo != null ? mOwnerInfo.equals(session.mOwnerInfo)
-                : session.mOwnerInfo == null;
-
+        if (!Objects.equals(mSessionId, session.mSessionId)) return false;
+        if (!Objects.equals(mShortMethodName, session.mShortMethodName)) return false;
+        if (!Objects.equals(mParentSession, session.mParentSession)) return false;
+        if (!Objects.equals(mChildSessions, session.mChildSessions)) return false;
+        return Objects.equals(mOwnerInfo, session.mOwnerInfo);
     }
 
     @Override
diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java
index 9d17219..00e344c 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -27,6 +27,7 @@
 import android.util.Base64;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.telecom.flags.Flags;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -36,10 +37,16 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * TODO: Create better Sessions Documentation
+ * SessionManager manages the active sessions in a HashMap, which maps the active thread(s) to the
+ * associated {@link Session}s.
+ * <p>
+ * Note: Sessions assume that session structure modification is synchronized on this object - only
+ * one thread can modify the structure of any Session at one time. Printing the current session to
+ * the log is not synchronized because we should not clean up a session chain while printing from
+ * another Thread. Either the Session chain is still active and can not be cleaned up yet, or the
+ * Session chain has ended and we are cleaning up.
  * @hide
  */
-
 public class SessionManager {
 
     // Currently using 3 letters, So don't exceed 64^3
@@ -54,11 +61,11 @@
     private Context mContext;
 
     @VisibleForTesting
-    public ConcurrentHashMap<Integer, Session> mSessionMapper = new ConcurrentHashMap<>(100);
+    public final ConcurrentHashMap<Integer, Session> mSessionMapper = new ConcurrentHashMap<>(64);
     @VisibleForTesting
     public java.lang.Runnable mCleanStaleSessions = () ->
             cleanupStaleSessions(getSessionCleanupTimeoutMs());
-    private Handler mSessionCleanupHandler = new Handler(Looper.getMainLooper());
+    private final Handler mSessionCleanupHandler = new Handler(Looper.getMainLooper());
 
     // Overridden in LogTest to skip query to ContentProvider
     private interface ISessionCleanupTimeoutMs {
@@ -83,7 +90,7 @@
     };
 
     // Usage is synchronized on this class.
-    private List<ISessionListener> mSessionListeners = new ArrayList<>();
+    private final List<ISessionListener> mSessionListeners = new ArrayList<>();
 
     public interface ISessionListener {
         /**
@@ -110,10 +117,19 @@
     }
 
     private synchronized void resetStaleSessionTimer() {
-        mSessionCleanupHandler.removeCallbacksAndMessages(null);
-        // Will be null in Log Testing
-        if (mCleanStaleSessions != null) {
-            mSessionCleanupHandler.postDelayed(mCleanStaleSessions, getSessionCleanupTimeoutMs());
+        if (!Flags.endSessionImprovements()) {
+            mSessionCleanupHandler.removeCallbacksAndMessages(null);
+            // Will be null in Log Testing
+            if (mCleanStaleSessions != null) {
+                mSessionCleanupHandler.postDelayed(mCleanStaleSessions,
+                        getSessionCleanupTimeoutMs());
+            }
+        } else {
+            if (mCleanStaleSessions != null
+                    && !mSessionCleanupHandler.hasCallbacks(mCleanStaleSessions)) {
+                mSessionCleanupHandler.postDelayed(mCleanStaleSessions,
+                        getSessionCleanupTimeoutMs());
+            }
         }
     }
 
@@ -147,13 +163,11 @@
             Session childSession = createSubsession(true);
             continueSession(childSession, shortMethodName);
             return;
-        } else {
-            // Only Log that we are starting the parent session.
-            Log.d(LOGGING_TAG, Session.START_SESSION);
         }
         Session newSession = new Session(getNextSessionID(), shortMethodName,
-                System.currentTimeMillis(), false, callerIdentification);
+                System.currentTimeMillis(), false, false, callerIdentification);
         mSessionMapper.put(threadId, newSession);
+        Log.d(LOGGING_TAG, Session.START_SESSION);
     }
 
     /**
@@ -179,17 +193,16 @@
         }
 
         // Create Session from Info and add to the sessionMapper under this ID.
-        Log.d(LOGGING_TAG, Session.START_EXTERNAL_SESSION);
         Session externalSession = new Session(Session.EXTERNAL_INDICATOR + sessionInfo.sessionId,
-                sessionInfo.methodPath, System.currentTimeMillis(),
-                false /*isStartedFromActiveSession*/, sessionInfo.ownerInfo);
-        externalSession.setIsExternal(true);
+                sessionInfo.methodPath, System.currentTimeMillis(), false, true,
+                sessionInfo.ownerInfo);
         // Mark the external session as already completed, since we have no way of knowing when
         // the external session actually has completed.
         externalSession.markSessionCompleted(Session.UNDEFINED);
         // Track the external session with the SessionMapper so that we can create and continue
         // an active subsession based on it.
         mSessionMapper.put(threadId, externalSession);
+        Log.d(LOGGING_TAG, Session.START_EXTERNAL_SESSION);
         // Create a subsession from this external Session parent node
         Session childSession = createSubsession();
         continueSession(childSession, shortMethodName);
@@ -226,13 +239,12 @@
         // Start execution time of the session will be overwritten in continueSession(...).
         Session newSubsession = new Session(threadSession.getNextChildId(),
                 threadSession.getShortMethodName(), System.currentTimeMillis(),
-                isStartedFromActiveSession, threadSession.getOwnerInfo());
+                isStartedFromActiveSession, false, threadSession.getOwnerInfo());
         threadSession.addChild(newSubsession);
         newSubsession.setParentSession(threadSession);
 
         if (!isStartedFromActiveSession) {
-            Log.v(LOGGING_TAG, Session.CREATE_SUBSESSION + " " +
-                    newSubsession.toString());
+            Log.v(LOGGING_TAG, Session.CREATE_SUBSESSION);
         } else {
             Log.v(LOGGING_TAG, Session.CREATE_SUBSESSION +
                     " (Invisible subsession)");
@@ -273,7 +285,7 @@
         }
 
         subsession.markSessionCompleted(Session.UNDEFINED);
-        endParentSessions(subsession);
+        cleanupSessionTreeAndNotify(subsession);
     }
 
     /**
@@ -328,7 +340,7 @@
         // Remove after completed so that reference still exists for logging the end events
         Session parentSession = completedSession.getParentSession();
         mSessionMapper.remove(threadId);
-        endParentSessions(completedSession);
+        cleanupSessionTreeAndNotify(completedSession);
         // If this subsession was started from a parent session using Log.startSession, return the
         // ThreadID back to the parent after completion.
         if (parentSession != null && !parentSession.isSessionCompleted() &&
@@ -337,8 +349,49 @@
         }
     }
 
+    /**
+     * Move up the session tree and remove completed sessions until we either hit a session that was
+     * not completed yet or we reach the root node. Once we reach the root node, we will report the
+     * session times to session complete listeners.
+     * @param session The Session to clean up.
+     */
+    private void cleanupSessionTreeAndNotify(Session session) {
+        if (session == null) return;
+        if (!Flags.endSessionImprovements()) {
+            endParentSessionsRecursive(session);
+            return;
+        }
+        Session currSession = session;
+        // Traverse upwards and unlink until we either hit the root node or a node that isn't
+        // complete yet.
+        while (currSession != null) {
+            if (!currSession.isSessionCompleted() || !currSession.getChildSessions().isEmpty()) {
+                // We will return once the active session is completed.
+                return;
+            }
+            Session parentSession = currSession.getParentSession();
+            currSession.setParentSession(null);
+            // The session is either complete when we have reached the top node or we have reached
+            // the node where the parent is external. We only want to report the time it took to
+            // complete the local session, so for external nodes, report finished when the sub-node
+            // completes.
+            boolean reportSessionComplete =
+                    (parentSession == null && !currSession.isExternal())
+                            || (parentSession != null && parentSession.isExternal());
+            if (parentSession != null) parentSession.removeChild(currSession);
+            if (reportSessionComplete) {
+                long fullSessionTimeMs = System.currentTimeMillis()
+                        - currSession.getExecutionStartTimeMilliseconds();
+                Log.d(LOGGING_TAG, Session.END_SESSION + " (dur: " + fullSessionTimeMs
+                        + " ms): " + currSession);
+                notifySessionCompleteListeners(currSession.getShortMethodName(), fullSessionTimeMs);
+            }
+            currSession = parentSession;
+        }
+    }
+
     // Recursively deletes all complete parent sessions of the current subsession if it is a leaf.
-    private void endParentSessions(Session subsession) {
+    private void endParentSessionsRecursive(Session subsession) {
         // Session is not completed or not currently a leaf, so we can not remove because a child is
         // still running
         if (!subsession.isSessionCompleted() || subsession.getChildSessions().size() != 0) {
@@ -355,7 +408,7 @@
                         System.currentTimeMillis() - subsession.getExecutionStartTimeMilliseconds();
                 notifySessionCompleteListeners(subsession.getShortMethodName(), fullSessionTimeMs);
             }
-            endParentSessions(parentSession);
+            endParentSessionsRecursive(parentSession);
         } else {
             // All of the subsessions have been completed and it is time to report on the full
             // running time of the session.
@@ -370,8 +423,10 @@
     }
 
     private void notifySessionCompleteListeners(String methodName, long sessionTimeMs) {
-        for (ISessionListener l : mSessionListeners) {
-            l.sessionComplete(methodName, sessionTimeMs);
+        synchronized (mSessionListeners) {
+            for (ISessionListener l : mSessionListeners) {
+                l.sessionComplete(methodName, sessionTimeMs);
+            }
         }
     }
 
@@ -380,8 +435,8 @@
         return currentSession != null ? currentSession.toString() : "";
     }
 
-    public synchronized void registerSessionListener(ISessionListener l) {
-        if (l != null) {
+    public void registerSessionListener(ISessionListener l) {
+        synchronized (mSessionListeners) {
             mSessionListeners.add(l);
         }
     }
@@ -425,25 +480,30 @@
 
     @VisibleForTesting
     public synchronized void cleanupStaleSessions(long timeoutMs) {
-        String logMessage = "Stale Sessions Cleaned:\n";
+        StringBuilder logMessage = new StringBuilder("Stale Sessions Cleaned:");
         boolean isSessionsStale = false;
         long currentTimeMs = System.currentTimeMillis();
         // Remove references that are in the Session Mapper (causing GC to occur) on
-        // sessions that are lasting longer than LOGGING_SESSION_TIMEOUT_MS.
+        // sessions that are lasting longer than DEFAULT_SESSION_TIMEOUT_MS.
         // If this occurs, then there is most likely a Session active that never had
         // Log.endSession called on it.
         for (Iterator<ConcurrentHashMap.Entry<Integer, Session>> it =
              mSessionMapper.entrySet().iterator(); it.hasNext(); ) {
             ConcurrentHashMap.Entry<Integer, Session> entry = it.next();
             Session session = entry.getValue();
-            if (currentTimeMs - session.getExecutionStartTimeMilliseconds() > timeoutMs) {
+            long runTime = currentTimeMs - session.getExecutionStartTimeMilliseconds();
+            if (runTime > timeoutMs) {
                 it.remove();
-                logMessage += session.printFullSessionTree() + "\n";
+                logMessage.append("\n");
+                logMessage.append("[");
+                logMessage.append(runTime);
+                logMessage.append("ms] ");
+                logMessage.append(session.printFullSessionTree());
                 isSessionsStale = true;
             }
         }
         if (isSessionsStale) {
-            Log.w(LOGGING_TAG, logMessage);
+            Log.w(LOGGING_TAG, logMessage.toString());
         } else {
             Log.v(LOGGING_TAG, "No stale logging sessions needed to be cleaned...");
         }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 47f6764..02999c8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -253,7 +253,6 @@
      *
      * The default value is true.
      */
-    @FlaggedApi(Flags.FLAG_SHOW_CALL_ID_AND_CALL_WAITING_IN_ADDITIONAL_SETTINGS_MENU)
     public static final String KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL =
             "additional_settings_caller_id_visibility_bool";
 
@@ -263,7 +262,6 @@
      *
      * The default value is true.
      */
-    @FlaggedApi(Flags.FLAG_SHOW_CALL_ID_AND_CALL_WAITING_IN_ADDITIONAL_SETTINGS_MENU)
     public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL =
             "additional_settings_call_waiting_visibility_bool";
 
@@ -10558,7 +10556,6 @@
      * @see SubscriptionInfo#getServiceCapabilities()
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      */
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public static final String KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY =
             "cellular_service_capabilities_int_array";
    /**
@@ -11110,7 +11107,7 @@
         sDefaults.putString(KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "");
         sDefaults.putInt(KEY_NR_ADVANCED_BANDS_SECONDARY_TIMER_SECONDS_INT, 0);
         sDefaults.putBoolean(KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL, false);
-        sDefaults.putBoolean(KEY_NR_TIMERS_RESET_ON_VOICE_QOS_BOOL, true);
+        sDefaults.putBoolean(KEY_NR_TIMERS_RESET_ON_VOICE_QOS_BOOL, false);
         sDefaults.putBoolean(KEY_NR_TIMERS_RESET_ON_PLMN_CHANGE_BOOL, false);
         /* Default value is 1 hour. */
         sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 845449e..02030a1 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -19,6 +19,7 @@
 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -32,6 +33,7 @@
 import android.os.Build;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.Sms7BitEncodingTranslator;
@@ -1208,9 +1210,9 @@
     /**
      * Returns the recipient address(receiver) of this SMS message in String form or null if
      * unavailable.
-     * {@hide}
      */
     @Nullable
+    @FlaggedApi(Flags.FLAG_SUPPORT_SMS_OVER_IMS_APIS)
     public String getRecipientAddress() {
         return mWrappedSmsMessage.getRecipientAddress();
     }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 1089602..d164c88 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -951,7 +951,6 @@
      * @see SubscriptionManager#SERVICE_CAPABILITY_DATA
      */
     @NonNull
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public @SubscriptionManager.ServiceCapability Set<Integer> getServiceCapabilities() {
         return SubscriptionManager.getServiceCapabilitiesSet(mServiceCapabilities);
     }
@@ -1829,7 +1828,6 @@
          * @throws IllegalArgumentException when any capability is not supported.
          */
         @NonNull
-        @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
         public Builder setServiceCapabilities(
                 @NonNull @SubscriptionManager.ServiceCapability Set<Integer> capabilities) {
             int combinedCapabilities = 0;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 6faef7e..377e5f2 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1422,7 +1422,6 @@
      *
      * @see TelephonyManager#isDeviceVoiceCapable()
      */
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public static final int SERVICE_CAPABILITY_VOICE = 1;
 
     /**
@@ -1440,13 +1439,11 @@
      *
      * @see TelephonyManager#isDeviceSmsCapable()
      */
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public static final int SERVICE_CAPABILITY_SMS = 2;
 
     /**
      * Represents a value indicating the data calling capabilities of a subscription.
      */
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public static final int SERVICE_CAPABILITY_DATA = 3;
 
     /**
@@ -3474,14 +3471,62 @@
     @SystemApi
     public boolean canManageSubscription(@NonNull SubscriptionInfo info,
             @NonNull String packageName) {
+        if (Flags.hsumPackageManager()) {
+            return canManageSubscriptionAsUser(info, packageName, mContext.getUser());
+        } else {
+            if (info == null || info.getAccessRules() == null || packageName == null) {
+                return false;
+            }
+            PackageManager packageManager = mContext.getPackageManager();
+            PackageInfo packageInfo;
+            try {
+                packageInfo = packageManager.getPackageInfo(packageName,
+                        PackageManager.GET_SIGNING_CERTIFICATES);
+            } catch (PackageManager.NameNotFoundException e) {
+                logd("Unknown package: " + packageName);
+                return false;
+            }
+            for (UiccAccessRule rule : info.getAccessRules()) {
+                if (rule.getCarrierPrivilegeStatus(packageInfo)
+                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks whether the given app is authorized to manage the given subscription for given user.
+     *
+     * <p>An app can only be authorized if it is available to the given user and included in the
+     * {@link android.telephony.UiccAccessRule} of the {@link android.telephony.SubscriptionInfo}
+     * with the access status.
+     *
+     * <p>Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns
+     * true). To check for permissions for non-embedded subscription as well,
+     * see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}.
+     *
+     * @param info        The subscription to check.
+     * @param packageName Package name of the app to check.
+     * @param user        UserHandle to check
+     * @return whether the app is authorized to manage this subscription per its access rules.
+     *
+     * @see android.telephony.TelephonyManager#hasCarrierPrivileges
+     * @hide
+     */
+    public boolean canManageSubscriptionAsUser(@NonNull SubscriptionInfo info,
+            @NonNull String packageName, @NonNull UserHandle user) {
         if (info == null || info.getAccessRules() == null || packageName == null) {
             return false;
         }
-        PackageManager packageManager = mContext.getPackageManager();
+        PackageManager pm = mContext.getUser().equals(user)
+                ? mContext.getPackageManager()
+                : mContext.createContextAsUser(user, 0).getPackageManager();
         PackageInfo packageInfo;
         try {
-            packageInfo = packageManager.getPackageInfo(packageName,
-                PackageManager.GET_SIGNING_CERTIFICATES);
+            packageInfo = pm.getPackageInfo(packageName,
+                    PackageManager.GET_SIGNING_CERTIFICATES);
         } catch (PackageManager.NameNotFoundException e) {
             logd("Unknown package: " + packageName);
             return false;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fee4587..a7fe0cb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2127,7 +2127,6 @@
      * <p>On some devices, this settings activity may not exist. Callers should ensure that this
      * case is appropriately handled.
      */
-    @FlaggedApi(Flags.FLAG_RESET_MOBILE_NETWORK_SETTINGS)
     @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_RESET_MOBILE_NETWORK_SETTINGS =
             "android.telephony.action.RESET_MOBILE_NETWORK_SETTINGS";
@@ -6934,7 +6933,6 @@
      *
      * @see SubscriptionInfo#getServiceCapabilities()
      */
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public boolean isDeviceVoiceCapable() {
         return isVoiceCapable();
     }
@@ -6974,7 +6972,6 @@
      *
      * @see SubscriptionInfo#getServiceCapabilities()
      */
-    @FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
     public boolean isDeviceSmsCapable() {
         return isSmsCapable();
     }
@@ -8781,13 +8778,14 @@
      *   Authentication error, no memory space available in EFMUK
      *
      * @throws UnsupportedOperationException If the device does not have
-     *          {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+     *          {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} or doesn't support given
+     *          authType.
      */
     // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not
     // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
     // it's not public API.
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
-    public String getIccAuthentication(int appType,@AuthType int authType, String data) {
+    public String getIccAuthentication(int appType, @AuthType int authType, String data) {
         return getIccAuthentication(getSubId(), appType, authType, data);
     }
 
@@ -8812,10 +8810,14 @@
      *   Key freshness failure
      *   Authentication error, no memory space available
      *   Authentication error, no memory space available in EFMUK
+     * @throws UnsupportedOperationException If the device does not have
+     *          {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} or doesn't support given
+     *          authType.
      * @hide
      */
     @UnsupportedAppUsage
-    public String getIccAuthentication(int subId, int appType,@AuthType int authType, String data) {
+    public String getIccAuthentication(int subId, int appType, @AuthType int authType,
+            String data) {
         try {
             IPhoneSubInfo info = getSubscriberInfoService();
             if (info == null)
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index f2e3425..9ce8e80 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -352,7 +352,8 @@
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenActivity"
                   android:theme="@style/CutoutShortEdges"
                   android:label="SplitScreenPrimaryActivity"
-                  android:exported="true">
+                  android:exported="true"
+                  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
@@ -363,7 +364,8 @@
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenSecondaryActivity"
                   android:theme="@style/CutoutShortEdges"
                   android:label="SplitScreenSecondaryActivity"
-                  android:exported="true">
+                  android:exported="true"
+                  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 4ae06a4..7526737 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -46,6 +46,7 @@
 import com.android.modules.utils.testing.ExtendedMockitoRule
 import junitparams.JUnitParamsRunner
 import junitparams.Parameters
+import org.junit.After
 import org.junit.Assert.assertArrayEquals
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
@@ -128,6 +129,13 @@
         currentPid = Process.myPid()
     }
 
+    @After
+    fun teardown() {
+        if (this::inputManagerGlobalSession.isInitialized) {
+            inputManagerGlobalSession.close()
+        }
+    }
+
     private fun setupBehaviors() {
         Mockito.`when`(
             resources.getBoolean(
diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
index 9f4df90..c61a250 100644
--- a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
+++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
@@ -39,7 +39,6 @@
 import junit.framework.Assert.fail
 import org.hamcrest.Matchers.allOf
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TestName
@@ -108,7 +107,6 @@
         parser = InputJsonParser(instrumentation.context)
     }
 
-    @Ignore("b/366602644")
     @Test
     fun testEvemuRecording() {
         VirtualDisplayActivityScenario.AutoClose<CaptureEventActivity>(
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 0375f66..d9295dd 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -515,33 +515,27 @@
                 Install.single(APEX_V2));
     }
 
-    @Test
-    public void testGetStagedModuleNames() throws Exception {
-        // Before staging a session
-        String[] result = getPackageManagerNative().getStagedApexModuleNames();
-        assertThat(result).hasLength(0);
-        // Stage an apex
-        int sessionId = Install.single(APEX_V2).setStaged().commit();
-        result = getPackageManagerNative().getStagedApexModuleNames();
-        assertThat(result).hasLength(1);
-        assertThat(result).isEqualTo(new String[]{SHIM_APEX_PACKAGE_NAME});
-        // Abandon the session
-        InstallUtils.openPackageInstallerSession(sessionId).abandon();
-        result = getPackageManagerNative().getStagedApexModuleNames();
-        assertThat(result).hasLength(0);
+    private StagedApexInfo findStagedApexInfo(StagedApexInfo[] infos, String moduleName) {
+        for (StagedApexInfo info: infos) {
+            if (info.moduleName.equals(moduleName)) {
+                return info;
+            }
+        }
+        return null;
     }
 
     @Test
-    public void testGetStagedApexInfo() throws Exception {
-        // Ask for non-existing module
-        StagedApexInfo result = getPackageManagerNative().getStagedApexInfo("not found");
-        assertThat(result).isNull();
+    public void testGetStagedApexInfos() throws Exception {
+        // Not found before staging
+        StagedApexInfo[] result = getPackageManagerNative().getStagedApexInfos();
+        assertThat(findStagedApexInfo(result, TEST_APEX_PACKAGE_NAME)).isNull();
         // Stage an apex
         int sessionId = Install.single(TEST_APEX_CLASSPATH).setStaged().commit();
         // Query proper module name
-        result = getPackageManagerNative().getStagedApexInfo(TEST_APEX_PACKAGE_NAME);
-        assertThat(result.moduleName).isEqualTo(TEST_APEX_PACKAGE_NAME);
-        assertThat(result.hasClassPathJars).isTrue();
+        result = getPackageManagerNative().getStagedApexInfos();
+        StagedApexInfo found = findStagedApexInfo(result, TEST_APEX_PACKAGE_NAME);
+        assertThat(found).isNotNull();
+        assertThat(found.hasClassPathJars).isTrue();
         InstallUtils.openPackageInstallerSession(sessionId).abandon();
     }
 
@@ -573,14 +567,15 @@
         int sessionId = Install.single(APEX_V2).setStaged().commit();
         ArgumentCaptor<ApexStagedEvent> captor = ArgumentCaptor.forClass(ApexStagedEvent.class);
         verify(observer, timeout(5000)).onApexStaged(captor.capture());
-        assertThat(captor.getValue().stagedApexModuleNames).isEqualTo(
-                new String[] {SHIM_APEX_PACKAGE_NAME});
+        StagedApexInfo found =
+                findStagedApexInfo(captor.getValue().stagedApexInfos, SHIM_APEX_PACKAGE_NAME);
+        assertThat(found).isNotNull();
 
         // Abandon and verify observer is called
         Mockito.clearInvocations(observer);
         InstallUtils.openPackageInstallerSession(sessionId).abandon();
         verify(observer, timeout(5000)).onApexStaged(captor.capture());
-        assertThat(captor.getValue().stagedApexModuleNames).hasLength(0);
+        assertThat(captor.getValue().stagedApexInfos).hasLength(0);
     }
 
     @Test
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index f1fc503..97abcd7 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -592,23 +592,15 @@
     }
 
     @Test
-    public void testGetStagedModuleNames() throws Exception {
-        assumeTrue("Device does not support updating APEX",
-                mHostUtils.isApexUpdateSupported());
-
-        runPhase("testGetStagedModuleNames");
-    }
-
-    @Test
     @LargeTest
-    public void testGetStagedApexInfo() throws Exception {
+    public void testGetStagedApexInfos() throws Exception {
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
 
         pushTestApex(APEXD_TEST_APEX);
         getDevice().reboot();
 
-        runPhase("testGetStagedApexInfo");
+        runPhase("testGetStagedApexInfos");
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 4cb7c91..7e0bbc4 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -70,7 +70,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.Uri;
-import android.net.vcn.Flags;
 import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
@@ -85,7 +84,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.test.TestLooper;
-import android.platform.test.flag.junit.SetFlagsRule;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -104,7 +102,6 @@
 import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -122,8 +119,6 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class VcnManagementServiceTest {
-    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
     private static final String CONTEXT_ATTRIBUTION_TAG = "VCN";
     private static final String TEST_PACKAGE_NAME =
             VcnManagementServiceTest.class.getPackage().getName();
@@ -285,8 +280,6 @@
 
     @Before
     public void setUp() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENFORCE_MAIN_USER);
-
         doNothing()
                 .when(mMockContext)
                 .enforceCallingOrSelfPermission(
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index edad678..421e1ad 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -34,14 +34,12 @@
 import android.net.NetworkCapabilities;
 import android.net.TelephonyNetworkSpecifier;
 import android.net.vcn.FeatureFlags;
-import android.net.vcn.Flags;
 import android.os.Handler;
 import android.os.IPowerManager;
 import android.os.IThermalService;
 import android.os.ParcelUuid;
 import android.os.PowerManager;
 import android.os.test.TestLooper;
-import android.platform.test.flag.junit.SetFlagsRule;
 import android.telephony.TelephonyManager;
 
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -49,7 +47,6 @@
 import com.android.server.vcn.VcnNetworkProvider;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -57,8 +54,6 @@
 import java.util.UUID;
 
 public abstract class NetworkEvaluationTestBase {
-    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
     protected static final String SSID = "TestWifi";
     protected static final String SSID_OTHER = "TestWifiOther";
     protected static final String PLMN_ID = "123456";
@@ -120,10 +115,6 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS);
-        mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE);
-        mSetFlagsRule.enableFlags(Flags.FLAG_HANDLE_SEQ_NUM_LEAP);
-
         when(mNetwork.getNetId()).thenReturn(-1);
 
         mTestLooper = new TestLooper();
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 37b1687..5983cf1 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -28,8 +28,19 @@
 namespace aapt {
 
 static constexpr ApiVersion sDevelopmentSdkLevel = 10000;
+
+// clang-format off
 static constexpr StringPiece sDevelopmentSdkCodeNames[] = {
-    "Q"sv, "R"sv, "S"sv, "Sv2"sv, "Tiramisu"sv, "UpsideDownCake"sv, "VanillaIceCream"sv};
+    "Q"sv,
+    "R"sv,
+    "S"sv,
+    "Sv2"sv,
+    "Tiramisu"sv,
+    "UpsideDownCake"sv,
+    "VanillaIceCream"sv,
+    "Baklava"sv,
+};
+// clang-format on
 
 static constexpr auto sPrivacySandboxSuffix = "PrivacySandbox"sv;
 
diff --git a/tools/hoststubgen/.gitignore b/tools/hoststubgen/.gitignore
deleted file mode 100644
index 6453bde..0000000
--- a/tools/hoststubgen/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-out/
-*-out/
-*.log
diff --git a/tools/hoststubgen/OWNERS b/tools/hoststubgen/OWNERS
deleted file mode 100644
index 3d8888d..0000000
--- a/tools/hoststubgen/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file:platform/frameworks/base:/ravenwood/OWNERS
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING
deleted file mode 100644
index 856e6ee..0000000
--- a/tools/hoststubgen/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "imports": [
-    {
-      "path": "frameworks/base/ravenwood"
-    }
-  ]
-}
diff --git a/tools/hoststubgen/hoststubgen/.gitignore b/tools/hoststubgen/hoststubgen/.gitignore
deleted file mode 100644
index 0f38407..0000000
--- a/tools/hoststubgen/hoststubgen/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-framework-all-stub-out
\ No newline at end of file