diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index c30164c065af5edfc4240cf2ed56f5cf9160502f..003b7f87fa23fe365d98dca25d6d4cc85539bfc9 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -42,6 +42,7 @@ aconfig_srcjars = [
     ":android.credentials.flags-aconfig-java{.generated_srcjars}",
     ":android.view.contentprotection.flags-aconfig-java{.generated_srcjars}",
     ":android.service.voice.flags-aconfig-java{.generated_srcjars}",
+    ":android.service.autofill.flags-aconfig-java{.generated_srcjars}",
 ]
 
 filegroup {
@@ -416,3 +417,19 @@ java_aconfig_library {
     aconfig_declarations: "android.service.voice.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// Autofill
+aconfig_declarations {
+    name: "android.service.autofill.flags-aconfig",
+    package: "android.service.autofill",
+    srcs: [
+        "services/autofill/bugfixes.aconfig",
+        "services/autofill/features.aconfig"
+    ],
+}
+
+java_aconfig_library {
+    name: "android.service.autofill.flags-aconfig-java",
+    aconfig_declarations: "android.service.autofill.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index f252a0ba48cf7d35c1a5d48393d1135e28adfbce..158d914575c6c6c94fff049404cfd2efd5afdff9 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -1030,6 +1030,12 @@ public class DeviceIdleController extends SystemService
                 "light_idle_to_initial_flex";
         private static final String KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX = "light_max_idle_to_flex";
         private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
+        private static final String KEY_LIGHT_IDLE_INCREASE_LINEARLY =
+                "light_idle_increase_linearly";
+        private static final String KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS =
+                "light_idle_linear_increase_factor_ms";
+        private static final String KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS =
+                "light_idle_flex_linear_increase_factor_ms";
         private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
         private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
                 "light_idle_maintenance_min_budget";
@@ -1079,6 +1085,10 @@ public class DeviceIdleController extends SystemService
         private long mDefaultLightIdleTimeoutMaxFlex =
                 !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
         private float mDefaultLightIdleFactor = 2f;
+        private boolean mDefaultLightIdleIncreaseLinearly;
+        private long mDefaultLightIdleLinearIncreaseFactorMs = mDefaultLightIdleTimeout;
+        private long mDefaultLightIdleFlexLinearIncreaseFactorMs =
+                mDefaultLightIdleTimeoutInitialFlex;
         private long mDefaultLightMaxIdleTimeout =
                 !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
         private long mDefaultLightIdleMaintenanceMinBudget =
@@ -1173,6 +1183,37 @@ public class DeviceIdleController extends SystemService
          */
         public float LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
 
+        /**
+         * Whether to increase the light idle mode time linearly or exponentially.
+         * If true, will increase linearly
+         * (i.e. {@link #LIGHT_IDLE_TIMEOUT} + x * {@link #LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS}).
+         * If false, will increase by exponentially
+         * (i.e. {@link #LIGHT_IDLE_TIMEOUT} * ({@link #LIGHT_IDLE_FACTOR} ^ x)).
+         * This will also impact how the light idle flex value
+         * ({@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX}) is increased (using
+         * {@link #LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS} for the linear increase)..
+         *
+         * @see #KEY_LIGHT_IDLE_INCREASE_LINEARLY
+         */
+        public boolean LIGHT_IDLE_INCREASE_LINEARLY = mDefaultLightIdleIncreaseLinearly;
+
+        /**
+         * Amount of time to increase the light idle time by, if increasing it linearly.
+         *
+         * @see #KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS
+         * @see #LIGHT_IDLE_INCREASE_LINEARLY
+         */
+        public long LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleLinearIncreaseFactorMs;
+
+        /**
+         * Amount of time to increase the light idle flex time by, if increasing it linearly.
+         *
+         * @see #KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS
+         * @see #LIGHT_IDLE_INCREASE_LINEARLY
+         */
+        public long LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS =
+                mDefaultLightIdleFlexLinearIncreaseFactorMs;
+
         /**
          * This is the maximum time we will stay in light idle mode.
          *
@@ -1409,6 +1450,16 @@ public class DeviceIdleController extends SystemService
                     mDefaultLightIdleTimeoutMaxFlex);
             mDefaultLightIdleFactor = res.getFloat(
                     com.android.internal.R.integer.device_idle_light_idle_factor);
+            mDefaultLightIdleIncreaseLinearly = res.getBoolean(
+                    com.android.internal.R.bool.device_idle_light_idle_increase_linearly);
+            mDefaultLightIdleLinearIncreaseFactorMs = getTimeout(res.getInteger(
+                    com.android.internal.R.integer
+                            .device_idle_light_idle_linear_increase_factor_ms),
+                    mDefaultLightIdleLinearIncreaseFactorMs);
+            mDefaultLightIdleFlexLinearIncreaseFactorMs = getTimeout(res.getInteger(
+                    com.android.internal.R.integer
+                            .device_idle_light_idle_flex_linear_increase_factor_ms),
+                    mDefaultLightIdleFlexLinearIncreaseFactorMs);
             mDefaultLightMaxIdleTimeout = getTimeout(
                     res.getInteger(com.android.internal.R.integer.device_idle_light_max_idle_to_ms),
                     mDefaultLightMaxIdleTimeout);
@@ -1487,6 +1538,9 @@ public class DeviceIdleController extends SystemService
             LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = mDefaultLightIdleTimeoutInitialFlex;
             LIGHT_IDLE_TIMEOUT_MAX_FLEX = mDefaultLightIdleTimeoutMaxFlex;
             LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
+            LIGHT_IDLE_INCREASE_LINEARLY = mDefaultLightIdleIncreaseLinearly;
+            LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleLinearIncreaseFactorMs;
+            LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleFlexLinearIncreaseFactorMs;
             LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
             LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
             LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget;
@@ -1556,6 +1610,21 @@ public class DeviceIdleController extends SystemService
                             LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
                                     KEY_LIGHT_IDLE_FACTOR, mDefaultLightIdleFactor));
                             break;
+                        case KEY_LIGHT_IDLE_INCREASE_LINEARLY:
+                            LIGHT_IDLE_INCREASE_LINEARLY = properties.getBoolean(
+                                    KEY_LIGHT_IDLE_INCREASE_LINEARLY,
+                                    mDefaultLightIdleIncreaseLinearly);
+                            break;
+                        case KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS:
+                            LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = properties.getLong(
+                                    KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS,
+                                    mDefaultLightIdleLinearIncreaseFactorMs);
+                            break;
+                        case KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS:
+                            LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = properties.getLong(
+                                    KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS,
+                                    mDefaultLightIdleFlexLinearIncreaseFactorMs);
+                            break;
                         case KEY_LIGHT_MAX_IDLE_TIMEOUT:
                             LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(
                                     KEY_LIGHT_MAX_IDLE_TIMEOUT, mDefaultLightMaxIdleTimeout);
@@ -1716,6 +1785,20 @@ public class DeviceIdleController extends SystemService
             pw.print(LIGHT_IDLE_FACTOR);
             pw.println();
 
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_INCREASE_LINEARLY); pw.print("=");
+            pw.print(LIGHT_IDLE_INCREASE_LINEARLY);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS);
+            pw.print("=");
+            pw.print(LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS);
+            pw.print("=");
+            pw.print(LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT, pw);
             pw.println();
@@ -3694,10 +3777,18 @@ public class DeviceIdleController extends SystemService
                 }
                 mMaintenanceStartTime = 0;
                 scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex, true);
-                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
-                        (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
-                mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
-                        (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
+                if (!mConstants.LIGHT_IDLE_INCREASE_LINEARLY) {
+                    mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
+                            (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
+                    mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
+                            (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
+                } else {
+                    mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
+                            mNextLightIdleDelay + mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS);
+                    mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
+                            mNextLightIdleDelayFlex
+                                    + mConstants.LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS);
+                }
                 moveToLightStateLocked(LIGHT_STATE_IDLE, reason);
                 addEvent(EVENT_LIGHT_IDLE, null);
                 mGoingIdleWakeLock.acquire();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 358c8e72064b3f7c0a5724214291ad6eddbd3058..a99eeb0c36d830e1528e8b676829d954617cb33b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3946,7 +3946,7 @@ package android.content.pm {
     field public static final int DELETE_FAILED_OWNER_BLOCKED = -4; // 0xfffffffc
     field public static final int DELETE_KEEP_DATA = 1; // 0x1
     field public static final int DELETE_SUCCEEDED = 1; // 0x1
-    field public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID = "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";
+    field @FlaggedApi("android.permission.flags.device_aware_permission_apis") public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID = "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";
     field public static final String EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES";
     field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
     field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 2fb428b3e0b47421cd0f7d5fa76d2e595886daae..a84845a15a79217b2404d5a174f043d28d10bba6 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -239,6 +239,12 @@ public final class CompanionDeviceManager {
     @SystemApi(client = MODULE_LIBRARIES)
     public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
 
+    /**
+     * The length limit of Association tag.
+     * @hide
+     */
+    private static final int ASSOCIATION_TAG_LENGTH_LIMIT = 100;
+
     /**
      * Callback for applications to receive updates about and the outcome of
      * {@link AssociationRequest} issued via {@code associate()} call.
@@ -1409,7 +1415,7 @@ public final class CompanionDeviceManager {
     /**
      * Sets the {@link AssociationInfo#getTag() tag} for this association.
      *
-     * <p>The length of the tag must be at most 20 characters.
+     * <p>The length of the tag must be at most 100 characters to save disk space.
      *
      * <p>This allows to store useful information about the associated devices.
      *
@@ -1421,8 +1427,8 @@ public final class CompanionDeviceManager {
     public void setAssociationTag(int associationId, @NonNull String tag) {
         Objects.requireNonNull(tag, "tag cannot be null");
 
-        if (tag.length() > 20) {
-            throw new IllegalArgumentException("Length of the tag must be at most 20 characters");
+        if (tag.length() > ASSOCIATION_TAG_LENGTH_LIMIT) {
+            throw new IllegalArgumentException("Length of the tag must be at most 100 characters");
         }
 
         try {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3fc515d3d37d2a52778badd6759b7f0eef4e6f34..8fbe50c3288164889ff907e5582e6b763b9d184b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4802,6 +4802,7 @@ public abstract class PackageManager {
      * @hide
      */
     @SystemApi
+    @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID =
             "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";
 
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index c4d307073d122fe0e5b694f782f07a38b9b4dd8b..a150187bbc6c5ef0de3f33b49516382695911cfc 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -23,6 +23,8 @@ import android.graphics.GraphicBuffer;
 import android.window.PictureInPictureSurfaceTransaction;
 import android.window.TaskSnapshot;
 
+import com.android.internal.os.IResultReceiver;
+
 /**
  * Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the
  * runner control certain aspects of the recents animation, and to notify window manager when the
@@ -58,7 +60,7 @@ interface IRecentsAnimationController {
      *                          top resumed app, false otherwise.
      */
     @UnsupportedAppUsage
-    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint);
+    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint, in IResultReceiver finishCb);
 
     /**
      * Called by the handler to indicate that the recents animation input consumer should be
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 2761aaeb4a7d7f7473560951267910a3706a6c63..45b3fdd7e5bc57f18cef6563d84656d5be241533 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static com.android.window.flags.Flags.surfaceTrustedOverlay;
+
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.graphics.Matrix;
@@ -35,7 +37,6 @@ import java.lang.ref.WeakReference;
  * @hide
  */
 public final class InputWindowHandle {
-
     /**
      * An internal annotation for all the {@link android.os.InputConfig} flags that can be
      * specified to {@link #inputConfig} to control the behavior of an input window. Only the
@@ -59,7 +60,6 @@ public final class InputWindowHandle {
             InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,
             InputConfig.IS_WALLPAPER,
             InputConfig.PAUSE_DISPATCHING,
-            InputConfig.TRUSTED_OVERLAY,
             InputConfig.WATCH_OUTSIDE_TOUCH,
             InputConfig.SLIPPERY,
             InputConfig.DISABLE_USER_ACTIVITY,
@@ -272,4 +272,13 @@ public final class InputWindowHandle {
         }
         this.inputConfig &= ~inputConfig;
     }
+
+    public void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc,
+            boolean isTrusted) {
+        if (surfaceTrustedOverlay()) {
+            t.setTrustedOverlay(sc, isTrusted);
+        } else if (isTrusted) {
+            inputConfig |= InputConfig.TRUSTED_OVERLAY;
+        }
+    }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e64274ec38925f69b35f5758762c0ad3dcc36aa5..2f4bea0270c1819a1291e1823448af2ed0738f2d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1850,6 +1850,8 @@ public interface WindowManager extends ViewManager {
                         to = "PHONE"),
                 @ViewDebug.IntToString(from = TYPE_SYSTEM_ALERT,
                         to = "SYSTEM_ALERT"),
+                @ViewDebug.IntToString(from = TYPE_KEYGUARD,
+                        to = "KEYGUARD"),
                 @ViewDebug.IntToString(from = TYPE_TOAST,
                         to = "TOAST"),
                 @ViewDebug.IntToString(from = TYPE_SYSTEM_OVERLAY,
@@ -1898,6 +1900,8 @@ public interface WindowManager extends ViewManager {
                         to = "PRIVATE_PRESENTATION"),
                 @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION,
                         to = "VOICE_INTERACTION"),
+                @ViewDebug.IntToString(from = TYPE_ACCESSIBILITY_OVERLAY,
+                        to = "ACCESSIBILITY_OVERLAY"),
                 @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING,
                         to = "VOICE_INTERACTION_STARTING"),
                 @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER,
@@ -1907,7 +1911,13 @@ public interface WindowManager extends ViewManager {
                 @ViewDebug.IntToString(from = TYPE_SCREENSHOT,
                         to = "SCREENSHOT"),
                 @ViewDebug.IntToString(from = TYPE_APPLICATION_OVERLAY,
-                        to = "APPLICATION_OVERLAY")
+                        to = "APPLICATION_OVERLAY"),
+                @ViewDebug.IntToString(from = TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+                        to = "ACCESSIBILITY_MAGNIFICATION_OVERLAY"),
+                @ViewDebug.IntToString(from = TYPE_NOTIFICATION_SHADE,
+                        to = "NOTIFICATION_SHADE"),
+                @ViewDebug.IntToString(from = TYPE_STATUS_BAR_ADDITIONAL,
+                        to = "STATUS_BAR_ADDITIONAL")
         })
         @WindowType
         public int type;
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index a0d58001a30d1f8d8e4f1ab23fe8125ee08fc802..e31ad82d3f5577738cb3f619a2dbac5637a86286 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -4,5 +4,5 @@ flag {
     namespace: "accessibility"
     name: "force_invert_color"
     description: "Enable force force-dark for smart inversion and dark theme everywhere"
-    bug: "239594271"
+    bug: "282821643"
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
new file mode 100644
index 0000000000000000000000000000000000000000..1b98806a0f01535696e42740ee3df7158e60c2b9
--- /dev/null
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -0,0 +1,11 @@
+package: "com.android.window.flags"
+
+# Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes
+
+flag {
+    namespace: "window_surfaces"
+    name: "surface_trusted_overlay"
+    description: "Whether to add trusted overlay flag on the SurfaceControl or the InputWindow"
+    is_fixed_read_only: true
+    bug: "292032926"
+}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 1bfb51cc4b82148169643cfcb6d16c0ca8cc30a2..6e836e077e4446e1f3c84a8276cb66dd1692e870 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -837,25 +837,41 @@ public class InteractionJankMonitor {
 
     @WorkerThread
     private void updateProperties(DeviceConfig.Properties properties) {
-        mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
-                DEFAULT_SAMPLING_INTERVAL);
-        mTraceThresholdMissedFrames = properties.getInt(SETTINGS_THRESHOLD_MISSED_FRAMES_KEY,
-                DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES);
-        mTraceThresholdFrameTimeMillis = properties.getInt(
-                SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY,
-                DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS);
-        // Never allow the debug overlay to be used on user builds
-        boolean debugOverlayEnabled = Build.IS_DEBUGGABLE && properties.getBoolean(
-                SETTINGS_DEBUG_OVERLAY_ENABLED_KEY,
-                DEFAULT_DEBUG_OVERLAY_ENABLED);
-        if (debugOverlayEnabled && mDebugOverlay == null) {
-            mDebugOverlay = new InteractionMonitorDebugOverlay(mLock, mDebugBgColor, mDebugYOffset);
-        } else if (!debugOverlayEnabled && mDebugOverlay != null) {
-            mDebugOverlay.dispose();
-            mDebugOverlay = null;
+        for (String property : properties.getKeyset()) {
+            switch (property) {
+                case SETTINGS_SAMPLING_INTERVAL_KEY:
+                    mSamplingInterval = properties.getInt(property, DEFAULT_SAMPLING_INTERVAL);
+                    break;
+                case SETTINGS_THRESHOLD_MISSED_FRAMES_KEY:
+                    mTraceThresholdMissedFrames =
+                            properties.getInt(property, DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES);
+                    break;
+                case SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY:
+                    mTraceThresholdFrameTimeMillis =
+                            properties.getInt(property, DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS);
+                    break;
+                case SETTINGS_ENABLED_KEY:
+                    mEnabled = properties.getBoolean(property, DEFAULT_ENABLED);
+                    break;
+                case SETTINGS_DEBUG_OVERLAY_ENABLED_KEY:
+                    // Never allow the debug overlay to be used on user builds
+                    boolean debugOverlayEnabled = Build.IS_DEBUGGABLE
+                            && properties.getBoolean(property, DEFAULT_DEBUG_OVERLAY_ENABLED);
+                    if (debugOverlayEnabled && mDebugOverlay == null) {
+                        mDebugOverlay = new InteractionMonitorDebugOverlay(
+                                mLock, mDebugBgColor, mDebugYOffset);
+                    } else if (!debugOverlayEnabled && mDebugOverlay != null) {
+                        mDebugOverlay.dispose();
+                        mDebugOverlay = null;
+                    }
+                    break;
+                default:
+                    if (DEBUG) {
+                        Log.d(TAG, "Got a change event for an unknown property: "
+                                + property + " => " + properties.getString(property, ""));
+                    }
+            }
         }
-        // The memory visibility is powered by the volatile field, mEnabled.
-        mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
     }
 
     @VisibleForTesting
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 06e69f2d985956155168b7a01af63ebf2e5a6006..fd435d0595c21aeaa796821fae467a35a217a2fb 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -222,6 +222,7 @@ public final class FloatingActionMode extends ActionMode {
     private boolean isContentRectWithinBounds() {
         mContext.getDisplayNoVerify().getRealSize(mDisplaySize);
         mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
+        mScreenRect.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);
 
         return intersectsClosed(mContentRectOnScreen, mScreenRect)
             && intersectsClosed(mContentRectOnScreen, mViewRectOnScreen);
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 8b6c90141bb76c95d47853111de2b46280fb34c0..27f8138ac5e371f3aa8bacac7a5fb4cbead0b5c7 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -60,10 +60,11 @@
                     android:gravity="center"
                     android:textAppearance="@style/AutofillSaveUiTitle">
                 </TextView>
-                <LinearLayout
+                <FrameLayout
                     android:id="@+id/autofill_save_custom_subtitle"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
+                    android:minHeight="0dp"
                     android:visibility="gone"/>
 
             </LinearLayout>
diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml
index 98a5ff9c4a790b7886f7d16b5508d365038b3297..bc9ca3decec32c6521ec629b81e475c030a9a94f 100644
--- a/core/res/res/values/config_device_idle.xml
+++ b/core/res/res/values/config_device_idle.xml
@@ -42,6 +42,15 @@
     <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FACTOR -->
     <item name="device_idle_light_idle_factor" format="float" type="integer">2.0</item>
 
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_INCREASE_LINEARLY -->
+    <bool name="device_idle_light_idle_increase_linearly">false</bool>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS -->
+    <integer name="device_idle_light_idle_linear_increase_factor_ms">300000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS -->
+    <integer name="device_idle_light_idle_flex_linear_increase_factor_ms">60000</integer>
+
     <!-- Default for DeviceIdleController.Constants.LIGHT_MAX_IDLE_TIMEOUT -->
     <integer name="device_idle_light_max_idle_to_ms">900000</integer>
 
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index c68e6ad15546c317c2857f37152da5a46428b8e2..3ba150bcdd44f18ac4224db76d40865335d5d3e5 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -73,7 +73,7 @@
          CarrierConfigManager#KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_STRING_ARRAY.
          If 0, the device always switch to the higher score SIM.
          If < 0, the network type and signal strength based auto switch is disabled. -->
-    <integer name="auto_data_switch_score_tolerance">-1</integer>
+    <integer name="auto_data_switch_score_tolerance">4000</integer>
     <java-symbol type="integer" name="auto_data_switch_score_tolerance" />
 
     <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 193f3adeedea4e4c906c445fff6991e81e74b88b..7f3069542306751eb6e57501bdd4b2350593962e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4537,7 +4537,10 @@
   <java-symbol type="integer" name="device_idle_light_idle_to_init_flex_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_to_max_flex_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_factor" />
+  <java-symbol type="bool" name="device_idle_light_idle_increase_linearly" />
   <java-symbol type="integer" name="device_idle_light_max_idle_to_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_linear_increase_factor_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_flex_linear_increase_factor_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_maintenance_min_budget_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_maintenance_max_budget_ms" />
   <java-symbol type="integer" name="device_idle_min_light_maintenance_time_ms" />
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index 85d54e02d318076a63a6f4ed56a6087f823560aa..054d10c336e6058320455106a783cbfb835712e7 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -38,7 +38,7 @@ android_test {
     static_libs: [
         "services.core",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
         "testng",
         "mockito-target-extended",
     ],
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index a1952282dd0b7351debfdd8768e315932f9cf132..824f5910f96c31b7437dd82382b671d93693471a 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -16,20 +16,20 @@
 
 package com.android.server.broadcastradio.aidl;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.after;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.app.compat.CompatChanges;
 import android.graphics.Bitmap;
@@ -81,8 +81,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
     private static final int USER_ID_1 = 11;
     private static final int USER_ID_2 = 12;
-    private static final VerificationWithTimeout CALLBACK_TIMEOUT =
-            timeout(/* millis= */ 200);
+    private static final int CALLBACK_TIMEOUT_MS = 200;
+    private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS);
     private static final int SIGNAL_QUALITY = 90;
     private static final long AM_FM_FREQUENCY_SPACING = 500;
     private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
@@ -166,12 +166,12 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
     @Before
     public void setup() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
         doReturn(true).when(() -> CompatChanges.isChangeEnabled(
                 eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
+        doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier();
+        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
         doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser());
-        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
                 AidlTestUtils.makeDefaultModuleProperties());
@@ -222,7 +222,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
             return Result.OK;
         }).when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean());
 
-        when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(null);
+        doReturn(null).when(mBroadcastRadioMock).getImage(anyInt());
 
         doAnswer(invocation -> {
             int configFlag = (int) invocation.getArguments()[0];
@@ -275,7 +275,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].setConfiguration(FM_BAND_CONFIG);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onConfigurationChanged(FM_BAND_CONFIG);
     }
 
@@ -446,25 +446,10 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].tune(initialSel);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(tuneInfo);
     }
 
-    @Test
-    public void tune_forSystemUser() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
-        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
-        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
-        ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        RadioManager.ProgramInfo tuneInfo =
-                AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
-        openAidlClients(/* numClients= */ 1);
-
-        mTunerSessions[0].tune(initialSel);
-
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
-    }
-
     @Test
     public void tune_withUnknownErrorFromHal_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
@@ -525,7 +510,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
@@ -604,7 +589,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(seekUpInfo);
     }
 
@@ -638,6 +623,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
         openAidlClients(/* numClients= */ 1);
         ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
         mTunerSessions[0].tune(initialSel);
+        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(any());
         doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mTunerSessions[0].cancel();
@@ -686,8 +672,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
     public void getImage_whenHalThrowsException_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.getImage(anyInt()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock)
+                .getImage(anyInt());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getImage(/* id= */ 1);
@@ -713,7 +699,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].startBackgroundScan();
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
+                .onBackgroundScanComplete();
     }
 
     @Test
@@ -905,7 +892,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
         mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
                 /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
+                .onProgramListUpdated(any());
     }
 
     @Test
@@ -1160,8 +1148,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
         Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",
                 "mockParam2", "mockValue2");
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.setParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock)
+                .setParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].setParameters(parametersSet);
@@ -1186,8 +1174,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
         openAidlClients(/* numClients= */ 1);
         List<String> parameterKeys = List.of("mockKey1", "mockKey2");
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.getParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock)
+                .getParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getParameters(parameterKeys);
@@ -1198,7 +1186,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
     }
 
     @Test
-    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback()
+    public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback()
             throws Exception {
         openAidlClients(1);
         doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
@@ -1206,7 +1194,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
         mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo(
                 AidlTestUtils.makeHalFmSelector(AM_FM_FREQUENCY_LIST[1]), SIGNAL_QUALITY));
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index fac9eaafe94c56de8bfb20c34040f05d4c52a6c7..3b9d7ba5de3eb68e4174c00f58338d72c0ddaacf 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -16,22 +16,22 @@
 
 package com.android.server.broadcastradio.hal2;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.after;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.graphics.Bitmap;
 import android.hardware.broadcastradio.V2_0.Constants;
@@ -78,8 +78,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
     private static final int USER_ID_1 = 11;
     private static final int USER_ID_2 = 12;
-    private static final VerificationWithTimeout CALLBACK_TIMEOUT =
-            timeout(/* millis= */ 200);
+    private static final int CALLBACK_TIMEOUT_MS = 200;
+    private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS);
     private static final int SIGNAL_QUALITY = 1;
     private static final long AM_FM_FREQUENCY_SPACING = 500;
     private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
@@ -113,7 +113,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
     @Before
     public void setup() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
+        doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier();
         doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
         doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser());
@@ -170,7 +170,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
             return Result.OK;
         }).when(mHalTunerSessionMock).scan(anyBoolean(), anyBoolean());
 
-        when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(new ArrayList<Byte>(0));
+        doReturn(new ArrayList<Byte>(0)).when(mBroadcastRadioMock).getImage(anyInt());
 
         doAnswer(invocation -> {
             int configFlag = (int) invocation.getArguments()[0];
@@ -227,7 +227,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].setConfiguration(FM_BAND_CONFIG);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onConfigurationChanged(FM_BAND_CONFIG);
     }
 
@@ -379,7 +379,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].tune(initialSel);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(tuneInfo);
     }
 
@@ -397,20 +397,6 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
                 .that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
     }
 
-    @Test
-    public void tune_forSystemUser() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
-        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
-        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
-        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
-        openAidlClients(/* numClients= */ 1);
-
-        mTunerSessions[0].tune(initialSel);
-
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
-    }
-
     @Test
     public void step_withDirectionUp() throws Exception {
         long initFreq = AM_FM_FREQUENCY_LIST[1];
@@ -455,7 +441,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
@@ -533,7 +519,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(seekUpInfo);
     }
 
@@ -562,18 +548,6 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
         verify(mHalTunerSessionMock).cancel();
     }
 
-    @Test
-    public void cancel_forNonCurrentUser() throws Exception {
-        openAidlClients(/* numClients= */ 1);
-        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        mTunerSessions[0].tune(initialSel);
-        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
-
-        mTunerSessions[0].cancel();
-
-        verify(mHalTunerSessionMock, never()).cancel();
-    }
-
     @Test
     public void cancel_forNonCurrentUser_doesNotCancel() throws Exception {
         openAidlClients(/* numClients= */ 1);
@@ -627,8 +601,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
     public void getImage_whenHalThrowsException_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.getImage(anyInt()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock).getImage(anyInt());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getImage(/* id= */ 1);
@@ -654,7 +627,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
         mTunerSessions[0].startBackgroundScan();
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
+                .onBackgroundScanComplete();
     }
 
     @Test
@@ -845,8 +819,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
         Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",
                 "mockParam2", "mockValue2");
         String exceptionMessage = "HAL service died.";
-        when(mHalTunerSessionMock.setParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock)
+                .setParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].setParameters(parametersSet);
@@ -871,8 +845,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
         openAidlClients(/* numClients= */ 1);
         List<String> parameterKeys = List.of("mockKey1", "mockKey2");
         String exceptionMessage = "HAL service died.";
-        when(mHalTunerSessionMock.getParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock)
+                .getParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getParameters(parameterKeys);
@@ -883,7 +857,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
     }
 
     @Test
-    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback()
+    public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback()
             throws Exception {
         openAidlClients(1);
         doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
@@ -891,7 +865,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
         mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo(
                 TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY));
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
index 8c5d6d5a76a1fb6145a72c1ae6546d6ac89f3d67..0e3bc6562edbd042fd24b681437c8c6bf92aee5c 100644
--- a/core/tests/GameManagerTests/Android.bp
+++ b/core/tests/GameManagerTests/Android.bp
@@ -30,7 +30,7 @@ android_test {
         "frameworks-base-testutils",
         "junit",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index 6f2366e325747e49c82a3aa1bf46453fda870860..b631df1fcf578e62992e859dbab92c970e0427e9 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -35,7 +35,7 @@ android_test {
         "frameworks-base-testutils",
         "platform-test-annotations",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp
index 52608351775cf45656b11b6f28cf74e7b0c2a8c6..1fb5f2c0789b10aa33ac408d61b33b7128c53fd6 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp
@@ -18,7 +18,7 @@ android_test {
         "platform-test-annotations",
         "platformprotosnano",
         "statsdprotolite",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: ["android.test.runner"],
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index 2b34ee2646f37b503731dfa2d782c6e2c222ee21..7c1ac487bfdbe481b32d93aca8a347809900d210 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -32,7 +32,7 @@ android_test {
     static_libs: [
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: ["general-tests"],
     sdk_version: "test_current",
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 04622fda75df1b78695dc471fbb6ef8ecd7f861b..81dab0833af1577256d9ab3f2b20626c4cb5754b 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -58,7 +58,7 @@ android_test {
         "androidx.test.uiautomator_uiautomator",
         "platform-test-annotations",
         "platform-compat-test-rules",
-        "truth-prebuilt",
+        "truth",
         "print-test-util-lib",
         "testng",
         "servicestests-utils",
@@ -149,7 +149,7 @@ android_library {
         "androidx.test.runner",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index 3d04937c91955502b8d0add14784d87f5e46b146..5f6eaf96a846e9a9f5b21f088740fc85cbf0618b 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -30,7 +30,7 @@ android_test {
         "frameworks-base-testutils",
         "guava-android-testlib",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
index fde7c08715c7995c4d6a58802f68769382e022ff..2d778b1218d2331206618053bd904ab373540514 100644
--- a/core/tests/mockingcoretests/Android.bp
+++ b/core/tests/mockingcoretests/Android.bp
@@ -38,7 +38,7 @@ android_test {
         "androidx.test.ext.junit",
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
         "testables",
     ],
 
diff --git a/core/tests/nfctests/Android.bp b/core/tests/nfctests/Android.bp
index c74600bbab22c11d6ff32c003f652a750277aac3..f81be494ad18338880743d07a36131587707d7f6 100644
--- a/core/tests/nfctests/Android.bp
+++ b/core/tests/nfctests/Android.bp
@@ -27,7 +27,7 @@ android_test {
         "androidx.test.ext.junit",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.runner",
diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp
index 063c5694ab5be4b2ae7e9edf20cd7ec204cb08f7..931eac515e31f5926db89858baaa337ad725bd2c 100644
--- a/core/tests/overlaytests/device_self_targeting/Android.bp
+++ b/core/tests/overlaytests/device_self_targeting/Android.bp
@@ -30,7 +30,7 @@ android_test {
         "androidx.test.runner",
         "androidx.test.ext.junit",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
 
     optimize: {
diff --git a/core/tests/packagemonitortests/Android.bp b/core/tests/packagemonitortests/Android.bp
index 7b5d7dff0a855aab7d3a1a51857ff9c925b78ce6..b08850e90d28fa9d899fc1fe3f6c5c8808d2f0fa 100644
--- a/core/tests/packagemonitortests/Android.bp
+++ b/core/tests/packagemonitortests/Android.bp
@@ -32,7 +32,7 @@ android_test {
         "compatibility-device-util-axt",
         "frameworks-base-testutils",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/privacytests/Android.bp b/core/tests/privacytests/Android.bp
index bc3dd810be8c125aeef7de6cd72b82684ee9c7fa..4e24cd5d91cb6acf00d774cb49a1687184f0dc26 100644
--- a/core/tests/privacytests/Android.bp
+++ b/core/tests/privacytests/Android.bp
@@ -14,7 +14,7 @@ android_test {
         "junit",
         "rappor-tests",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp
index 3798da592cd50461e77b15f69df9a881c9834544..580e73c331a15e5ecd2fe9d0d5bb0f07374b1a6a 100644
--- a/core/tests/utiltests/Android.bp
+++ b/core/tests/utiltests/Android.bp
@@ -33,7 +33,7 @@ android_test {
         "frameworks-base-testutils",
         "mockito-target-minus-junit4",
         "androidx.test.ext.junit",
-        "truth-prebuilt",
+        "truth",
         "servicestests-utils",
     ],
 
diff --git a/core/tests/vibrator/Android.bp b/core/tests/vibrator/Android.bp
index 829409a36986d9c5da2c3fef9667dcc1c88d3998..09608e9bf5074c62763c880a168b6bfa92631bd3 100644
--- a/core/tests/vibrator/Android.bp
+++ b/core/tests/vibrator/Android.bp
@@ -18,7 +18,7 @@ android_test {
         "androidx.test.runner",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "testng",
     ],
 
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index ad08026622d154b44ae11cea858221e9a70da8ba..c1d2235e3324168d569fe995fe292d3971074220 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -41,7 +41,7 @@ java_test_host {
     java_resource_dirs: ["tests/res"],
     java_resources: [":error_prone_android_framework_testdata"],
     static_libs: [
-        "truth-prebuilt",
+        "truth",
         "kxml2-2.3.0",
         "compile-testing-prebuilt",
         "error_prone_android_framework_lib",
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
index b6e743a2b7e1fc9f4079b31ef762183cf9f146c1..ed2ff2de245b6db6c6bcf18877dca3217f7c340f 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp
+++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
@@ -37,7 +37,7 @@ android_test {
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "platform-test-annotations",
     ],
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index f1ee8fa384858b66b4fc1ed867a7674bf7381ce2..a67821b7e819d5eda07be39583a2e3dc2af8813c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -318,7 +318,7 @@ public class BadgedImageView extends ConstraintLayout {
     /**
      * Animates the dot to the given scale, running the optional callback when the animation ends.
      */
-    private void animateDotScale(float toScale, @Nullable Runnable after) {
+    public void animateDotScale(float toScale, @Nullable Runnable after) {
         mDotIsAnimating = true;
 
         // Don't restart the animation if we're already animating to the given value.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index df19757203eb1c319d2b81111860dfc68121e27c..dc099d9abda4e5f1bc93cc8a30aa50aed53bc134 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -27,6 +27,7 @@ import android.graphics.drawable.ColorDrawable
 import android.graphics.drawable.InsetDrawable
 import android.util.PathParser
 import android.view.LayoutInflater
+import android.view.View.VISIBLE
 import android.widget.FrameLayout
 import com.android.launcher3.icons.BubbleIconFactory
 import com.android.wm.shell.R
@@ -156,7 +157,9 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl
 
     fun setShowDot(show: Boolean) {
         showDot = show
-        overflowBtn?.updateDotVisibility(true /* animate */)
+        if (overflowBtn?.visibility == VISIBLE) {
+            overflowBtn?.updateDotVisibility(true /* animate */)
+        }
     }
 
     /** Creates the expanded view for bubbles showing in the stack view. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index c124b532b89d08317349540f15e25f849df08ee8..2241c343a208bd53e572d5c8b80b1cb499bcd3a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1864,6 +1864,14 @@ public class BubbleStackView extends FrameLayout
                 : GONE);
     }
 
+    private void updateOverflowDotVisibility(boolean expanding) {
+        if (mBubbleOverflow.showDot()) {
+            mBubbleOverflow.getIconView().animateDotScale(expanding ? 1 : 0f, () -> {
+                mBubbleOverflow.setVisible(expanding ? VISIBLE : GONE);
+            });
+        }
+    }
+
     // via BubbleData.Listener
     void updateBubble(Bubble bubble) {
         animateInFlyoutForBubble(bubble);
@@ -2274,6 +2282,7 @@ public class BubbleStackView extends FrameLayout
             if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {
                 maybeShowManageEdu();
             }
+            updateOverflowDotVisibility(true /* expanding */);
         } /* after */);
         int index;
         if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
@@ -2405,11 +2414,15 @@ public class BubbleStackView extends FrameLayout
         // since we're about to animate collapsed.
         mExpandedAnimationController.notifyPreparingToCollapse();
 
+        updateOverflowDotVisibility(false /* expanding */);
         final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(
                 mStackAnimationController
                         .getStackPositionAlongNearestHorizontalEdge()
                 /* collapseTo */,
-                () -> mBubbleContainer.setActiveController(mStackAnimationController));
+                () -> {
+                    mBubbleContainer.setActiveController(mStackAnimationController);
+                    updateOverflowVisibility();
+                });
 
         final Runnable after = () -> {
             final BubbleViewProvider previouslySelected = mExpandedBubble;
@@ -2424,7 +2437,6 @@ public class BubbleStackView extends FrameLayout
                 Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
                         mExpandedBubble));
             }
-            updateOverflowVisibility();
             updateZOrder();
             updateBadges(true /* setBadgeForCollapsedStack */);
             afterExpandedViewAnimation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 4d7042bbb3d278730bc338c2c334605e56cc5522..738c94e82a950411aeb544ee6bf1f43d23c1a1c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -34,6 +34,8 @@ import androidx.dynamicanimation.animation.SpringForce;
 import com.android.wm.shell.R;
 import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BadgedImageView;
+import com.android.wm.shell.bubbles.BubbleOverflow;
 import com.android.wm.shell.bubbles.BubblePositioner;
 import com.android.wm.shell.bubbles.BubbleStackView;
 import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -63,6 +65,12 @@ public class ExpandedAnimationController
     /** Damping ratio for expand/collapse spring. */
     private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f;
 
+    /**
+     * Damping ratio for the overflow bubble spring; this is less bouncy so it doesn't bounce behind
+     * the top bubble when it goes to disappear.
+     */
+    private static final float DAMPING_RATIO_OVERFLOW_BOUNCY = 0.90f;
+
     /** Stiffness for the expand/collapse path-following animation. */
     private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 400;
 
@@ -274,9 +282,14 @@ public class ExpandedAnimationController
                 // of the screen where the bubble will be stacked.
                 path.lineTo(stackedX, p.y);
 
+                // The overflow should animate to the collapse point, so 0 offset.
+                final boolean isOverflow = bubble instanceof BadgedImageView
+                        && BubbleOverflow.KEY.equals(((BadgedImageView) bubble).getKey());
+                final float offsetY = isOverflow
+                        ? 0
+                        : Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx;
                 // Then, draw a line down to the stack position.
-                path.lineTo(stackedX, mCollapsePoint.y
-                        + Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx);
+                path.lineTo(stackedX, mCollapsePoint.y + offsetY);
             }
 
             // The lead bubble should be the bubble with the longest distance to travel when we're
@@ -505,8 +518,12 @@ public class ExpandedAnimationController
 
     @Override
     SpringForce getSpringForce(DynamicAnimation.ViewProperty property, View view) {
+        boolean isOverflow = (view instanceof BadgedImageView)
+                && BubbleOverflow.KEY.equals(((BadgedImageView) view).getKey());
         return new SpringForce()
-                .setDampingRatio(DAMPING_RATIO_MEDIUM_LOW_BOUNCY)
+                .setDampingRatio(isOverflow
+                        ? DAMPING_RATIO_OVERFLOW_BOUNCY
+                        : DAMPING_RATIO_MEDIUM_LOW_BOUNCY)
                 .setStiffness(SpringForce.STIFFNESS_LOW);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 11aa054676cb9f528ea313c7224eb2ef8f6fdd71..5dfba5e7ff1d5cf9faccebea8052d537710ebb4d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -494,13 +494,14 @@ public abstract class WMShellModule {
             ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
             @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
             LaunchAdjacentController launchAdjacentController,
+            RecentsTransitionHandler recentsTransitionHandler,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
                 displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
                 transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler,
                 toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository,
-                launchAdjacentController, mainExecutor);
+                launchAdjacentController, recentsTransitionHandler, mainExecutor);
     }
 
     @WMSingleton
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 09ba4f79326ecde091bae099e7d46dec4053056f..412a5b5a6997a73dc307cb88a81e5ba903aeb9ba 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
@@ -60,6 +60,8 @@ import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.recents.RecentsTransitionHandler
+import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.splitscreen.SplitScreenController
 import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ENTER_DESKTOP
 import com.android.wm.shell.sysui.ShellCommandHandler
@@ -68,7 +70,6 @@ import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.sysui.ShellSharedConstants
 import com.android.wm.shell.transition.OneShotRemoteHandler
 import com.android.wm.shell.transition.Transitions
-import com.android.wm.shell.transition.Transitions.TransitionHandler
 import com.android.wm.shell.util.KtProtoLog
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
 import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
@@ -93,6 +94,7 @@ class DesktopTasksController(
         ToggleResizeDesktopTaskTransitionHandler,
         private val desktopModeTaskRepository: DesktopModeTaskRepository,
         private val launchAdjacentController: LaunchAdjacentController,
+        private val recentsTransitionHandler: RecentsTransitionHandler,
         @ShellMainThread private val mainExecutor: ShellExecutor
 ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler {
 
@@ -119,6 +121,8 @@ class DesktopTasksController(
             com.android.wm.shell.R.dimen.desktop_mode_transition_area_width
         )
 
+    private var recentsAnimationRunning = false
+
     // This is public to avoid cyclic dependency; it is set by SplitScreenController
     lateinit var splitScreenController: SplitScreenController
 
@@ -139,6 +143,19 @@ class DesktopTasksController(
         )
         transitions.addHandler(this)
         desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor)
+
+        recentsTransitionHandler.addTransitionStateListener(
+            object : RecentsTransitionStateListener {
+                override fun onAnimationStateChanged(running: Boolean) {
+                    KtProtoLog.v(
+                        WM_SHELL_DESKTOP_MODE,
+                        "DesktopTasksController: recents animation state changed running=%b",
+                        running
+                    )
+                    recentsAnimationRunning = running
+                }
+            }
+        )
     }
 
     /** Show all tasks, that are part of the desktop, on top of launcher */
@@ -644,6 +661,10 @@ class DesktopTasksController(
         val triggerTask = request.triggerTask
         val shouldHandleRequest =
             when {
+                recentsAnimationRunning -> {
+                    reason = "recents animation is running"
+                    false
+                }
                 // Only handle open or to front transitions
                 request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {
                     reason = "transition type not handled (${request.type})"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index ead2f9cbd1addffd907c1ee4286f9fa552239b0e..d31476c638907c7529380f47da3983afb8d4f9b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -54,6 +54,7 @@ import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -279,7 +280,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
             mDeathHandler = () -> {
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                         "[%d] RecentsController.DeathRecipient: binder died", mInstanceId);
-                finish(mWillFinishToHome, false /* leaveHint */);
+                finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */);
             };
             try {
                 mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
@@ -313,7 +314,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
                 }
             }
             if (mFinishCB != null) {
-                finishInner(toHome, false /* userLeave */);
+                finishInner(toHome, false /* userLeave */, null /* finishCb */);
             } else {
                 cleanUp();
             }
@@ -670,7 +671,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
                 // now and let it do its animation (since recents is going to be occluded).
                 sendCancelWithSnapshots();
                 mExecutor.executeDelayed(
-                        () -> finishInner(true /* toHome */, false /* userLeaveHint */), 0);
+                        () -> finishInner(true /* toHome */, false /* userLeaveHint */,
+                                null /* finishCb */), 0);
                 return;
             }
             if (recentsOpening != null) {
@@ -899,11 +901,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
 
         @Override
         @SuppressLint("NewApi")
-        public void finish(boolean toHome, boolean sendUserLeaveHint) {
-            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint));
+        public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {
+            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb));
         }
 
-        private void finishInner(boolean toHome, boolean sendUserLeaveHint) {
+        private void finishInner(boolean toHome, boolean sendUserLeaveHint,
+                IResultReceiver runnerFinishCb) {
             if (mFinishCB == null) {
                 Slog.e(TAG, "Duplicate call to finish");
                 return;
@@ -993,6 +996,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
             }
             cleanUp();
             finishCB.onTransitionFinished(wct.isEmpty() ? null : wct);
+            if (runnerFinishCb != null) {
+                try {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                            "[%d] RecentsController.finishInner: calling finish callback",
+                            mInstanceId);
+                    runnerFinishCb.send(0, null);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to report transition finished", e);
+                }
+            }
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 83dc7fa5e869aaa478e505ad2d52983d088e4fd8..e828eedc275c7671c262567180a4da14cdc55fd5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+
 import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
@@ -693,9 +694,19 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        Transitions.TransitionFinishCallback finishCB = wct -> {
+            mixed.mInFlightSubAnimations--;
+            if (mixed.mInFlightSubAnimations == 0) {
+                mActiveTransitions.remove(mixed);
+                finishCallback.onTransitionFinished(wct);
+            }
+        };
+
+        mixed.mInFlightSubAnimations++;
         boolean consumed = mRecentsHandler.startAnimation(
-                mixed.mTransition, info, startTransaction, finishTransaction, finishCallback);
+                mixed.mTransition, info, startTransaction, finishTransaction, finishCB);
         if (!consumed) {
+            mixed.mInFlightSubAnimations--;
             return false;
         }
         if (mDesktopTasksController != null) {
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 e0635ac2e19a38915b50bbf1dfdca9ef6d065b90..de03f5826925615a47e9778cc329cb616b7a48ae 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
@@ -322,7 +322,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
         final Runnable onAnimFinish = () -> {
             if (!animations.isEmpty()) return;
             mAnimations.remove(transition);
-            info.releaseAllSurfaces();
             finishCallback.onTransitionFinished(null /* wct */);
         };
 
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 54f94986d90cf4416f5890bd596f2de09aef0d0d..d09a90cd7dc76c042dd705cc72efaf039e732e58 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -45,7 +45,7 @@ android_test {
         "kotlinx-coroutines-core",
         "mockito-kotlin2",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "platform-test-annotations",
         "servicestests-utils",
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index dea161786da2825abda381ba16932ca8c8bcc9c7..ebcb6407a6fd913da1086c88c61dc06c487a88c5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -54,6 +54,8 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreef
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
+import com.android.wm.shell.recents.RecentsTransitionHandler
+import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.splitscreen.SplitScreenController
 import com.android.wm.shell.sysui.ShellCommandHandler
 import com.android.wm.shell.sysui.ShellController
@@ -101,11 +103,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
     @Mock lateinit var launchAdjacentController: LaunchAdjacentController
     @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration
     @Mock lateinit var splitScreenController: SplitScreenController
+    @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler
 
     private lateinit var mockitoSession: StaticMockitoSession
     private lateinit var controller: DesktopTasksController
     private lateinit var shellInit: ShellInit
     private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository
+    private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener
 
     private val shellExecutor = TestShellExecutor()
     // Mock running tasks are registered here so we can get the list from mock shell task organizer
@@ -126,6 +130,10 @@ class DesktopTasksControllerTest : ShellTestCase() {
         controller.splitScreenController = splitScreenController
 
         shellInit.init()
+
+        val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java)
+        verify(recentsTransitionHandler).addTransitionStateListener(captor.capture())
+        recentsTransitionStateListener = captor.value
     }
 
     private fun createController(): DesktopTasksController {
@@ -144,6 +152,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
             mToggleResizeDesktopTaskTransitionHandler,
             desktopModeTaskRepository,
             launchAdjacentController,
+            recentsTransitionHandler,
             shellExecutor
         )
     }
@@ -355,7 +364,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
 
     @Test
     fun moveToDesktop_splitTaskExitsSplit() {
-        var task = setUpSplitScreenTask()
+        val task = setUpSplitScreenTask()
         controller.moveToDesktop(desktopModeWindowDecoration, task)
         val wct = getLatestMoveToDesktopWct()
         assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
@@ -367,7 +376,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
 
     @Test
     fun moveToDesktop_fullscreenTaskDoesNotExitSplit() {
-        var task = setUpFullscreenTask()
+        val task = setUpFullscreenTask()
         controller.moveToDesktop(desktopModeWindowDecoration, task)
         val wct = getLatestMoveToDesktopWct()
         assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
@@ -665,6 +674,20 @@ class DesktopTasksControllerTest : ShellTestCase() {
         assertThat(controller.handleRequest(Binder(), createTransition(task))).isNull()
     }
 
+    @Test
+    fun handleRequest_recentsAnimationRunning_returnNull() {
+        // Set up a visible freeform task so a fullscreen task should be converted to freeform
+        val freeformTask = setUpFreeformTask()
+        markTaskVisible(freeformTask)
+
+        // Mark recents animation running
+        recentsTransitionStateListener.onAnimationStateChanged(true)
+
+        // Open a fullscreen task, check that it does not result in a WCT with changes to it
+        val fullscreenTask = createFullscreenTask()
+        assertThat(controller.handleRequest(Binder(), createTransition(fullscreenTask))).isNull()
+    }
+
     @Test
     fun stashDesktopApps_stateUpdates() {
         whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp
index 64b53cbb5c5a724d57e229d0dd1b52321cf7a860..4dafd0aa6df41cf2f2be2c0d5af8a6ff29f983c3 100644
--- a/libs/dream/lowlight/tests/Android.bp
+++ b/libs/dream/lowlight/tests/Android.bp
@@ -34,7 +34,7 @@ android_test {
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
         "testables",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/libs/securebox/tests/Android.bp b/libs/securebox/tests/Android.bp
index 7df546ae0ff6649b26714265ce158b878149eb11..80b501da1aa57c3a390444d8df3eda871127a998 100644
--- a/libs/securebox/tests/Android.bp
+++ b/libs/securebox/tests/Android.bp
@@ -32,7 +32,7 @@ android_test {
         "platform-test-annotations",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index ca20225e8885b04c8ecea4f176199c610ecfa2bc..bdd7afeb2f658eb4c05d729cf19ef67a3b74801c 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -22,7 +22,7 @@ android_test {
         "android-ex-camera2",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         "libdexmakerjvmtiagent",
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index 4cccf897279805b2f31d832cfdf0dd2d92ab605a..61b18c88e7345117f43fb527cb835645cade46c4 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -24,7 +24,7 @@ android_test {
         "compatibility-device-util-axt",
         "mockito-target-minus-junit4",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: ["general-tests"],
     platform_apis: true,
diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp
index e313c46d1973cb29eef67360eb359fe2eba9a8ea..48cd8b69ade82d1f3716906e4994cdcacb0eec76 100644
--- a/media/tests/projection/Android.bp
+++ b/media/tests/projection/Android.bp
@@ -30,7 +30,7 @@ android_test {
         "platform-test-annotations",
         "testng",
         "testables",
-        "truth-prebuilt",
+        "truth",
         "platform-compat-test-rules",
     ],
 
diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp
index 633f1861092110a2a57f64e8f074189943f0742f..86c62ef299e4c340c622c70c0c70c6ab7773f620 100644
--- a/packages/ExternalStorageProvider/tests/Android.bp
+++ b/packages/ExternalStorageProvider/tests/Android.bp
@@ -25,7 +25,7 @@ android_test {
     static_libs: [
         "androidx.test.rules",
         "mockito-target",
-        "truth-prebuilt",
+        "truth",
     ],
 
     certificate: "platform",
diff --git a/packages/FusedLocation/Android.bp b/packages/FusedLocation/Android.bp
index 64b4c54e74ad38610699e01051d728f8dc7abb62..61a82701d1553006d5f77f3d5a680a5704dd3411 100644
--- a/packages/FusedLocation/Android.bp
+++ b/packages/FusedLocation/Android.bp
@@ -47,7 +47,7 @@ android_test {
     test_config: "test/AndroidTest.xml",
     srcs: [
         "test/src/**/*.java",
-        "src/**/*.java",  // include real sources because we're forced to test this directly
+        "src/**/*.java", // include real sources because we're forced to test this directly
     ],
     libs: [
         "android.test.base",
@@ -60,9 +60,9 @@ android_test {
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     platform_apis: true,
     certificate: "platform",
-    test_suites: ["device-tests"]
+    test_suites: ["device-tests"],
 }
diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp
index 4031cd7f7a6f070582432edeae0f875f798ee6e3..639d1a7a7f559e5544d51f01ac8dcd35c6ed2629 100644
--- a/packages/SettingsLib/Spa/testutils/Android.bp
+++ b/packages/SettingsLib/Spa/testutils/Android.bp
@@ -31,7 +31,7 @@ android_library {
         "androidx.compose.ui_ui-test-manifest",
         "androidx.lifecycle_lifecycle-runtime-testing",
         "mockito-kotlin2",
-        "truth-prebuilt",
+        "truth",
     ],
     kotlincflags: [
         "-Xjvm-default=all",
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index b03c43cbdee5ebaed620520ce64152c32431c587..4b4caf5a620ecfec619b28305af4548f5b98395d 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -52,7 +52,7 @@ android_test {
         "flag-junit",
         "mockito-target-minus-junit4",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibSettingsSpinner",
         "SettingsLibUsageProgressBarPreference",
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index dd9cb9cf7abe45300d1c07147fd8cb142f60e26c..2d875cf7244d76a4d6262faa93269cc23f103637 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -96,6 +96,6 @@ java_library {
     libs: [
         "Robolectric_all-target_upstream",
         "mockito-robolectric-prebuilt",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/packages/SettingsLib/tests/unit/Android.bp b/packages/SettingsLib/tests/unit/Android.bp
index 19ab1c69e98c60fa3fcd37cbae21ab4bd93f20ac..6d6e2ff8e59b18c4c0430d40362c3604763c9fcd 100644
--- a/packages/SettingsLib/tests/unit/Android.bp
+++ b/packages/SettingsLib/tests/unit/Android.bp
@@ -31,6 +31,6 @@ android_test {
         "SettingsLib",
         "androidx.test.ext.junit",
         "androidx.test.runner",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 92ebe09fa441c648d1052f8e96c736819a79180f..f4ca260d4d8918139477d371411e010b3c22b43b 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -64,7 +64,7 @@ android_test {
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibDisplayUtils",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.base",
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 3c57852759193fa4b7c9143fd3667f07b1572313..e40fcb2a633b85a239130117eb4581085fe17850 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -466,7 +466,7 @@ android_library {
         "hamcrest-library",
         "androidx.test.rules",
         "testables",
-        "truth-prebuilt",
+        "truth",
         "monet",
         "libmonet",
         "dagger2",
@@ -583,7 +583,7 @@ android_robolectric_test {
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
-        "truth-prebuilt",
+        "truth",
     ],
 
     upstream: true,
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 008732e787f1302e9b7d240dcc99fb322836816a..96e1e3fa68a7f1a48d08a0361f4317a3e930d1dc 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -63,6 +63,7 @@ public class AccessibilityMenuService extends AccessibilityService
 
     private static final String TAG = "A11yMenuService";
     private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L;
+    private static final long TAKE_SCREENSHOT_DELAY_MS = 100L;
 
     private static final int BRIGHTNESS_UP_INCREMENT_GAMMA =
             (int) Math.ceil(BrightnessUtils.GAMMA_SPACE_MAX * 0.11f);
@@ -301,7 +302,14 @@ public class AccessibilityMenuService extends AccessibilityService
         } else if (viewTag == ShortcutId.ID_NOTIFICATION_VALUE.ordinal()) {
             performGlobalActionInternal(GLOBAL_ACTION_NOTIFICATIONS);
         } else if (viewTag == ShortcutId.ID_SCREENSHOT_VALUE.ordinal()) {
-            performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT);
+            if (Flags.a11yMenuHideBeforeTakingAction()) {
+                // Delay before taking a screenshot to give time for the UI to close.
+                mHandler.postDelayed(
+                        () -> performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT),
+                        TAKE_SCREENSHOT_DELAY_MS);
+            } else {
+                performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT);
+            }
         }
 
         if (!Flags.a11yMenuHideBeforeTakingAction()) {
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp
index 538ecb3d438d512c3cf167b31a3efee9e75fa9b0..3fc351c32ec1a24340e1e98a456deb697e024759 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp
@@ -32,7 +32,7 @@ android_test {
         "androidx.test.ext.junit",
         "compatibility-device-util-axt",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     srcs: [
         "src/**/*.java",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 437f8afa8d7016d8e3feec8c3dae03888f0a8342..18117a890298807c8df42e918f22b049111dab6b 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -13,3 +13,11 @@ flag {
     description: "Enables all the sysui classic flags that are marked as being in teamfood"
     bug: "302578396"
 }
+
+flag {
+    name: "notifications_footer_view_refactor"
+    namespace: "systemui"
+    description: "Enables the refactored version of the footer view in the notification shade "
+        "(containing the \"Clear all\" button). Should not bring any behavior changes"
+    bug: "293167744"
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 0f2e4bace46d552f48ba417f19ed1741d45ade22..4aac27932924baf54ce6346b430130379eb7a57b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -39,6 +39,7 @@ import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.animation.Interpolator
 import android.view.animation.PathInterpolator
+import androidx.annotation.AnyThread
 import androidx.annotation.BinderThread
 import androidx.annotation.UiThread
 import com.android.app.animation.Interpolators
@@ -149,6 +150,10 @@ class ActivityLaunchAnimator(
             override fun onLaunchAnimationProgress(linearProgress: Float) {
                 listeners.forEach { it.onLaunchAnimationProgress(linearProgress) }
             }
+
+            override fun onLaunchAnimationCancelled() {
+                listeners.forEach { it.onLaunchAnimationCancelled() }
+            }
         }
 
     /**
@@ -191,6 +196,7 @@ class ActivityLaunchAnimator(
                     "ActivityLaunchAnimator.callback must be set before using this animator"
                 )
         val runner = createRunner(controller)
+        val runnerDelegate = runner.delegate!!
         val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
 
         // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the
@@ -241,12 +247,15 @@ class ActivityLaunchAnimator(
         // If we expect an animation, post a timeout to cancel it in case the remote animation is
         // never started.
         if (willAnimate) {
-            runner.delegate.postTimeout()
+            runnerDelegate.postTimeout()
 
             // Hide the keyguard using the launch animation instead of the default unlock animation.
             if (hideKeyguardWithAnimation) {
                 callback.hideKeyguardWithAnimation(runner)
             }
+        } else {
+            // We need to make sure delegate references are dropped to avoid memory leaks.
+            runner.dispose()
         }
     }
 
@@ -344,6 +353,13 @@ class ActivityLaunchAnimator(
          */
         fun onLaunchAnimationEnd() {}
 
+        /**
+         * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
+         * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
+         * before the cancellation.
+         */
+        fun onLaunchAnimationCancelled() {}
+
         /** Called when an activity launch animation made progress. */
         fun onLaunchAnimationProgress(linearProgress: Float) {}
     }
@@ -426,6 +442,39 @@ class ActivityLaunchAnimator(
         fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {}
     }
 
+    /**
+     * Invokes [onAnimationComplete] when animation is either cancelled or completed. Delegates all
+     * events to the passed [delegate].
+     */
+    @VisibleForTesting
+    inner class DelegatingAnimationCompletionListener(
+        private val delegate: Listener?,
+        private val onAnimationComplete: () -> Unit
+    ) : Listener {
+        var cancelled = false
+
+        override fun onLaunchAnimationStart() {
+            delegate?.onLaunchAnimationStart()
+        }
+
+        override fun onLaunchAnimationProgress(linearProgress: Float) {
+            delegate?.onLaunchAnimationProgress(linearProgress)
+        }
+
+        override fun onLaunchAnimationEnd() {
+            delegate?.onLaunchAnimationEnd()
+            if (!cancelled) {
+                onAnimationComplete.invoke()
+            }
+        }
+
+        override fun onLaunchAnimationCancelled() {
+            cancelled = true
+            delegate?.onLaunchAnimationCancelled()
+            onAnimationComplete.invoke()
+        }
+    }
+
     @VisibleForTesting
     inner class Runner(
         controller: Controller,
@@ -436,11 +485,21 @@ class ActivityLaunchAnimator(
         listener: Listener? = null
     ) : IRemoteAnimationRunner.Stub() {
         private val context = controller.launchContainer.context
-        internal val delegate: AnimationDelegate
+
+        // This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
+        // etc.) are possible. So we need to make sure we drop any references that might
+        // transitively cause leaks when we're done with animation.
+        @VisibleForTesting var delegate: AnimationDelegate?
 
         init {
             delegate =
-                AnimationDelegate(controller, callback, listener, launchAnimator, disableWmTimeout)
+                AnimationDelegate(
+                    controller,
+                    callback,
+                    DelegatingAnimationCompletionListener(listener, this::dispose),
+                    launchAnimator,
+                    disableWmTimeout
+                )
         }
 
         @BinderThread
@@ -451,14 +510,33 @@ class ActivityLaunchAnimator(
             nonApps: Array<out RemoteAnimationTarget>?,
             finishedCallback: IRemoteAnimationFinishedCallback?
         ) {
+            val delegate = delegate
             context.mainExecutor.execute {
-                delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+                if (delegate == null) {
+                    Log.i(TAG, "onAnimationStart called after completion")
+                    // Animation started too late and timed out already. We need to still
+                    // signal back that we're done with it.
+                    finishedCallback?.onAnimationFinished()
+                } else {
+                    delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+                }
             }
         }
 
         @BinderThread
         override fun onAnimationCancelled() {
-            context.mainExecutor.execute { delegate.onAnimationCancelled() }
+            val delegate = delegate
+            context.mainExecutor.execute {
+                delegate ?: Log.wtf(TAG, "onAnimationCancelled called after completion")
+                delegate?.onAnimationCancelled()
+            }
+        }
+
+        @AnyThread
+        fun dispose() {
+            // Drop references to animation controller once we're done with the animation
+            // to avoid leaking.
+            context.mainExecutor.execute { delegate = null }
         }
     }
 
@@ -584,6 +662,7 @@ class ActivityLaunchAnimator(
                     )
                 }
                 controller.onLaunchAnimationCancelled()
+                listener?.onLaunchAnimationCancelled()
                 return
             }
 
@@ -821,6 +900,7 @@ class ActivityLaunchAnimator(
                 Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]")
             }
             controller.onLaunchAnimationCancelled()
+            listener?.onLaunchAnimationCancelled()
         }
 
         @UiThread
@@ -842,6 +922,7 @@ class ActivityLaunchAnimator(
                 )
             }
             controller.onLaunchAnimationCancelled()
+            listener?.onLaunchAnimationCancelled()
         }
 
         private fun IRemoteAnimationFinishedCallback.invoke() {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
index 88944f10eab9e79084694fd203c2c7b0f50e8fe6..60c3fd3c4cdb30fca0b74f2701b13706f7ad1a6b 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -108,7 +108,7 @@ private fun CoroutineScope.animate(
 ) {
     val fromScene = layoutImpl.state.transitionState.currentScene
     val isUserInput =
-        (layoutImpl.state.transitionState as? TransitionState.Transition)?.isUserInputDriven
+        (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
             ?: false
 
     val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
@@ -119,9 +119,23 @@ private fun CoroutineScope.animate(
     val targetProgress = if (reversed) 0f else 1f
     val transition =
         if (reversed) {
-            OneOffTransition(target, fromScene, currentScene = target, isUserInput, animatable)
+            OneOffTransition(
+                fromScene = target,
+                toScene = fromScene,
+                currentScene = target,
+                isUserInput,
+                isUserInputOngoing = false,
+                animatable,
+            )
         } else {
-            OneOffTransition(fromScene, target, currentScene = target, isUserInput, animatable)
+            OneOffTransition(
+                fromScene = fromScene,
+                toScene = target,
+                currentScene = target,
+                isUserInput,
+                isUserInputOngoing = false,
+                animatable,
+            )
         }
 
     // Change the current layout state to use this new transition.
@@ -142,7 +156,8 @@ private class OneOffTransition(
     override val fromScene: SceneKey,
     override val toScene: SceneKey,
     override val currentScene: SceneKey,
-    override val isUserInputDriven: Boolean,
+    override val isInitiatedByUserInput: Boolean,
+    override val isUserInputOngoing: Boolean,
     private val animatable: Animatable<Float, AnimationVector1D>,
 ) : TransitionState.Transition {
     override val progress: Float
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index ccdec6ea8c5e525ff3f97de0ce490011b4bc352a..1b79dbdee5104eafc7b3a321773c30e9b098b229 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -52,7 +52,14 @@ sealed class ObservableTransitionState {
          * scene, this value will remain true after the pointer is no longer touching the screen and
          * will be true in any transition created to animate back to the original position.
          */
-        val isUserInputDriven: Boolean,
+        val isInitiatedByUserInput: Boolean,
+
+        /**
+         * Whether user input is currently driving the transition. For example, if a user is
+         * dragging a pointer, this emits true. Once they lift their finger, this emits false while
+         * the transition completes/settles.
+         */
+        val isUserInputOngoing: Flow<Boolean>,
     ) : ObservableTransitionState()
 }
 
@@ -73,7 +80,8 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans
                             fromScene = state.fromScene,
                             toScene = state.toScene,
                             progress = snapshotFlow { state.progress },
-                            isUserInputDriven = state.isUserInputDriven,
+                            isInitiatedByUserInput = state.isInitiatedByUserInput,
+                            isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
                         )
                     }
                 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 7a21211c3ddeada5408d27c59620c34ede5c9306..b9f83c545122ede4b7b37c8e3346a97e3629567c 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -70,6 +70,9 @@ sealed interface TransitionState {
         val progress: Float
 
         /** Whether the transition was triggered by user input rather than being programmatic. */
-        val isUserInputDriven: Boolean
+        val isInitiatedByUserInput: Boolean
+
+        /** Whether user input is currently driving the transition. */
+        val isUserInputOngoing: Boolean
     }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
index 1cbfe3057ff00d2e63dc3ea7e6bb1774931eb47d..e275fcaf45722a9980efcad9c548620752f446ae 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -66,7 +66,7 @@ internal fun Modifier.swipeToScene(
     // swipe in the other direction.
     val startDragImmediately =
         state == transition &&
-            transition.isAnimatingOffset &&
+            !transition.isUserInputOngoing &&
             !currentScene.shouldEnableSwipes(orientation.opposite())
 
     // The velocity threshold at which the intent of the user is to swipe up or down. It is the same
@@ -126,7 +126,7 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition
 
     override val progress: Float
         get() {
-            val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
+            val offset = if (isUserInputOngoing) dragOffset else offsetAnimatable.value
             if (distance == 0f) {
                 // This can happen only if fromScene == toScene.
                 error(
@@ -137,16 +137,15 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition
             return offset / distance
         }
 
-    override val isUserInputDriven = true
+    override val isInitiatedByUserInput = true
+
+    var _isUserInputOngoing by mutableStateOf(false)
+    override val isUserInputOngoing: Boolean
+        get() = _isUserInputOngoing
 
     /** The current offset caused by the drag gesture. */
     var dragOffset by mutableFloatStateOf(0f)
 
-    /**
-     * Whether the offset is animated (the user lifted their finger) or if it is driven by gesture.
-     */
-    var isAnimatingOffset by mutableStateOf(false)
-
     /** The animatable used to animate the offset once the user lifted its finger. */
     val offsetAnimatable = Animatable(0f, visibilityThreshold = OffsetVisibilityThreshold)
 
@@ -209,9 +208,11 @@ private fun onDragStarted(
     transition: SwipeTransition,
     orientation: Orientation,
 ) {
+    transition._isUserInputOngoing = true
+
     if (layoutImpl.state.transitionState == transition) {
         // This [transition] was already driving the animation: simply take over it.
-        if (transition.isAnimatingOffset) {
+        if (!transition.isUserInputOngoing) {
             // Stop animating and start from where the current offset. Setting the animation job to
             // `null` will effectively cancel the animation.
             transition.stopOffsetAnimation()
@@ -456,30 +457,29 @@ private fun CoroutineScope.animateOffset(
 ) {
     transition.startOffsetAnimation {
         launch {
-                if (!transition.isAnimatingOffset) {
-                    transition.offsetAnimatable.snapTo(transition.dragOffset)
-                }
-                transition.isAnimatingOffset = true
-
-                transition.offsetAnimatable.animateTo(
-                    targetOffset,
-                    // TODO(b/290184746): Make this spring spec configurable.
-                    spring(
-                        stiffness = Spring.StiffnessMediumLow,
-                        visibilityThreshold = OffsetVisibilityThreshold
-                    ),
-                    initialVelocity = initialVelocity,
-                )
+            if (transition.isUserInputOngoing) {
+                transition.offsetAnimatable.snapTo(transition.dragOffset)
+            }
+            transition._isUserInputOngoing = false
+
+            transition.offsetAnimatable.animateTo(
+                targetOffset,
+                // TODO(b/290184746): Make this spring spec configurable.
+                spring(
+                    stiffness = Spring.StiffnessMediumLow,
+                    visibilityThreshold = OffsetVisibilityThreshold
+                ),
+                initialVelocity = initialVelocity,
+            )
 
-                // Now that the animation is done, the state should be idle. Note that if the state
-                // was changed since this animation started, some external code changed it and we
-                // shouldn't do anything here. Note also that this job will be cancelled in the case
-                // where the user intercepts this swipe.
-                if (layoutImpl.state.transitionState == transition) {
-                    layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
-                }
+            // Now that the animation is done, the state should be idle. Note that if the state
+            // was changed since this animation started, some external code changed it and we
+            // shouldn't do anything here. Note also that this job will be cancelled in the case
+            // where the user intercepts this swipe.
+            if (layoutImpl.state.transitionState == transition) {
+                layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
             }
-            .also { it.invokeOnCompletion { transition.isAnimatingOffset = false } }
+        }
     }
 }
 
diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp
index 52c63854f62f77051568cb129a0055d66eac983e..8e9c5864ce706164250a075c6ba4877875a53263 100644
--- a/packages/SystemUI/compose/core/tests/Android.bp
+++ b/packages/SystemUI/compose/core/tests/Android.bp
@@ -43,7 +43,7 @@ android_test {
         "androidx.compose.ui_ui-test-junit4",
         "androidx.compose.ui_ui-test-manifest",
 
-        "truth-prebuilt",
+        "truth",
     ],
 
     kotlincflags: ["-Xjvm-default=all"],
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 2232370f3dc02feb56e6e79d49ddac3d3753ce89..53ed2b5d3317b3320c440a390cb96ef7407141f3 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -122,7 +122,8 @@ class SwipeToSceneTest {
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
         assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
-        assertThat(transition.isUserInputDriven).isTrue()
+        assertThat(transition.isInitiatedByUserInput).isTrue()
+        assertThat(transition.isUserInputOngoing).isTrue()
 
         // Release the finger. We should now be animating back to A (currentScene = SceneA) given
         // that 55dp < positional threshold.
@@ -134,7 +135,8 @@ class SwipeToSceneTest {
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
         assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
-        assertThat(transition.isUserInputDriven).isTrue()
+        assertThat(transition.isInitiatedByUserInput).isTrue()
+        assertThat(transition.isUserInputOngoing).isFalse()
 
         // Wait for the animation to finish. We should now be in scene A.
         rule.waitForIdle()
@@ -156,7 +158,8 @@ class SwipeToSceneTest {
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
         assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
-        assertThat(transition.isUserInputDriven).isTrue()
+        assertThat(transition.isInitiatedByUserInput).isTrue()
+        assertThat(transition.isUserInputOngoing).isTrue()
 
         // Release the finger. We should now be animating to C (currentScene = SceneC) given
         // that 56dp >= positional threshold.
@@ -168,7 +171,8 @@ class SwipeToSceneTest {
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)
         assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
-        assertThat(transition.isUserInputDriven).isTrue()
+        assertThat(transition.isInitiatedByUserInput).isTrue()
+        assertThat(transition.isUserInputOngoing).isFalse()
 
         // Wait for the animation to finish. We should now be in scene C.
         rule.waitForIdle()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 1f9c3e6d1ea1dd4d6c548f0873c5b96421dd7787..a33eac55ac3e76b7ddd0543de54dd29c4b4c4dfc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -23,11 +23,13 @@ import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.footer.ui.compose.QuickSettings
@@ -37,6 +39,7 @@ import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.shared.model.UserAction
 import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
 import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
@@ -98,12 +101,22 @@ private fun SceneScope.QuickSettingsScene(
                 .clickable(onClick = { viewModel.onContentClicked() })
                 .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
     ) {
-        ExpandedShadeHeader(
-            viewModel = viewModel.shadeHeaderViewModel,
-            createTintedIconManager = createTintedIconManager,
-            createBatteryMeterViewController = createBatteryMeterViewController,
-            statusBarIconController = statusBarIconController,
-        )
+        when (LocalWindowSizeClass.current.widthSizeClass) {
+            WindowWidthSizeClass.Compact ->
+                ExpandedShadeHeader(
+                    viewModel = viewModel.shadeHeaderViewModel,
+                    createTintedIconManager = createTintedIconManager,
+                    createBatteryMeterViewController = createBatteryMeterViewController,
+                    statusBarIconController = statusBarIconController,
+                )
+            else ->
+                CollapsedShadeHeader(
+                    viewModel = viewModel.shadeHeaderViewModel,
+                    createTintedIconManager = createTintedIconManager,
+                    createBatteryMeterViewController = createBatteryMeterViewController,
+                    statusBarIconController = statusBarIconController,
+                )
+        }
         Spacer(modifier = Modifier.height(16.dp))
         QuickSettings()
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index ef012660ad71e49bfd067b05cb446998fc9d304e..6359ce60ae701859f9fd58bb7b57a8065a265388 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -158,7 +158,8 @@ private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransi
                 fromScene = fromScene.toModel().key,
                 toScene = toScene.toModel().key,
                 progress = progress,
-                isUserInputDriven = isUserInputDriven,
+                isInitiatedByUserInput = isInitiatedByUserInput,
+                isUserInputOngoing = isUserInputOngoing,
             )
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 6629a259858708a187c08aa9d07d38a753b50864..591fa76f423f15b0ef2dba519af2e82072ca7fd3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.layout.widthIn
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.derivedStateOf
@@ -50,6 +51,7 @@ import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.ValueKey
 import com.android.compose.animation.scene.animateSharedFloatAsState
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.settingslib.Utils
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
@@ -98,12 +100,12 @@ fun SceneScope.CollapsedShadeHeader(
             ShadeHeader.Keys.transitionProgress,
             ShadeHeader.Elements.FormatPlaceholder
         )
-    val useExpandedFormat by
-        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }
 
     val cutoutWidth = LocalDisplayCutout.current.width()
     val cutoutLocation = LocalDisplayCutout.current.location
 
+    val useExpandedFormat = formatProgress.value > 0.5f || cutoutLocation != CutoutLocation.CENTER
+
     // This layout assumes it is globally positioned at (0, 0) and is the
     // same size as the screen.
     Layout(
@@ -131,6 +133,14 @@ fun SceneScope.CollapsedShadeHeader(
                 {
                     Row(horizontalArrangement = Arrangement.End) {
                         SystemIconContainer {
+                            when (LocalWindowSizeClass.current.widthSizeClass) {
+                                WindowWidthSizeClass.Medium,
+                                WindowWidthSizeClass.Expanded ->
+                                    ShadeCarrierGroup(
+                                        viewModel = viewModel,
+                                        modifier = Modifier.align(Alignment.CenterVertically),
+                                    )
+                            }
                             StatusIcons(
                                 viewModel = viewModel,
                                 createTintedIconManager = createTintedIconManager,
diff --git a/packages/SystemUI/customization/res/values-af/strings.xml b/packages/SystemUI/customization/res/values-af/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4c2c6275e6d8272679031fbf0ef2386f20f176a4
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-af/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Verstek vir digitaal"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-am/strings.xml b/packages/SystemUI/customization/res/values-am/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..847d7a541c950ae45063036c8cfce154a8cb3219
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-am/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ዲጂታል ነባሪ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ar/strings.xml b/packages/SystemUI/customization/res/values-ar/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..57d1612b337de43c2f2a61bd715b19787e3809b2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ar/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"رقمية تلقائية"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-as/strings.xml b/packages/SystemUI/customization/res/values-as/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2f3b64b9ceb6c85435163726eaaee4da8e760698
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-as/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটেল ডিফ’ল্ট"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-az/strings.xml b/packages/SystemUI/customization/res/values-az/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eb52f95a45258f9d51c0e18d3d081f74dd5b3380
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-az/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Rəqəmsal defolt"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..90e6678bdcd62a92dc938117751c6c5b6f1cd5e9
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalni podrazumevani"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-be/strings.xml b/packages/SystemUI/customization/res/values-be/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f327da2a40a4f42daf3d594d74d1c88d7edb64ca
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-be/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"электронны, стандартны шрыфт"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-bg/strings.xml b/packages/SystemUI/customization/res/values-bg/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6e3754a62a2949033163460eb093c2c54789b6fb
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-bg/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Стандартно дигитално"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-bn/strings.xml b/packages/SystemUI/customization/res/values-bn/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..adf1256b6c82fa46028c6e6102720e121fd7bc59
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-bn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটাল ডিফল্ট"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-bs/strings.xml b/packages/SystemUI/customization/res/values-bs/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8de04ab06503aea03ab4eb3607233fee69095bf2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-bs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalno zadano"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ca/strings.xml b/packages/SystemUI/customization/res/values-ca/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..967bb3f6d2f51ed04976e3e2b9a1b703f9257983
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ca/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminat"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-cs/strings.xml b/packages/SystemUI/customization/res/values-cs/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..45da4d759ad426229f855df2ce1e8e0a9afce036
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-cs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitální výchozí"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-da/strings.xml b/packages/SystemUI/customization/res/values-da/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ffaa8b167c85ea6d4ae7098fc6d078aa99e7043
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-da/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Standard (digital)"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-de/strings.xml b/packages/SystemUI/customization/res/values-de/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..64f95e05b2454c98868f0a5084146ec12e767a90
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-de/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital (Standard)"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-el/strings.xml b/packages/SystemUI/customization/res/values-el/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..57134b566d0816621758ffc903e9e3eb8c82f45f
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-el/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Ψηφιακή προεπιλογή"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-en-rAU/strings.xml b/packages/SystemUI/customization/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6110d5d5b092c5a57081f383a25f2be13da4f35
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-en-rAU/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-en-rCA/strings.xml b/packages/SystemUI/customization/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..79919c07d1894bac022815bb24313bf566bfd4c0
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-en-rCA/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for clock_default_description (5309401440896597541) -->
+    <skip />
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-en-rGB/strings.xml b/packages/SystemUI/customization/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6110d5d5b092c5a57081f383a25f2be13da4f35
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-en-rGB/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-en-rIN/strings.xml b/packages/SystemUI/customization/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6110d5d5b092c5a57081f383a25f2be13da4f35
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-en-rIN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-en-rXC/strings.xml b/packages/SystemUI/customization/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7c540dab2cfe27a1ea42722b88a1d18f1e32c47c
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-en-rXC/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‏‎Digital default‎‏‎‎‏‎"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-es-rUS/strings.xml b/packages/SystemUI/customization/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..59be786849e68ccaf7eacae2762645edc4986973
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-es-rUS/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Configuración predeterminada digital"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-es/strings.xml b/packages/SystemUI/customization/res/values-es/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..03ef0e5a8cea59ab580e8afad15ef5f06b37b133
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-es/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminada"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-et/strings.xml b/packages/SystemUI/customization/res/values-et/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fec793e99619d1c544bdff40a74b7130dcea6eff
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-et/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitaalne vaikimisi"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-eu/strings.xml b/packages/SystemUI/customization/res/values-eu/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a70c8085ccf0d1027dc0172a4a5faf68e55d68d1
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-eu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital lehenetsia"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-fa/strings.xml b/packages/SystemUI/customization/res/values-fa/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6426d5112528d9c3ff652a475b79633ddbdf5057
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-fa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"دیجیتال پیش‌فرض"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-fi/strings.xml b/packages/SystemUI/customization/res/values-fi/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9b19373a3765d6784b897fe1e378ce9a5102ddfe
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-fi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitaalinen (oletus)"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-fr-rCA/strings.xml b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bbd1208b1922b1159fd6967992e5f29ac17cb6f2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Numérique, par défaut"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-fr/strings.xml b/packages/SystemUI/customization/res/values-fr/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5579a427fe7197ca711ddacedf782e524a5ecee9
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-fr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Numérique par défaut"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-gl/strings.xml b/packages/SystemUI/customization/res/values-gl/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2da93c6f1e34934c7f5cf0749b0a0b46404a4ec0
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-gl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Predeterminada dixital"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-gu/strings.xml b/packages/SystemUI/customization/res/values-gu/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c578a2e2d322bde54641741b070fb07bc064170a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-gu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ડિજિટલ ડિફૉલ્ટ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hi/strings.xml b/packages/SystemUI/customization/res/values-hi/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6080f802af04fb8f1fded158d23b3d9e7316119c
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफ़ॉल्ट"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hr/strings.xml b/packages/SystemUI/customization/res/values-hr/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0a1440fb683b6205f1106f2aeb3218c8ce004348
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalni zadani"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hu/strings.xml b/packages/SystemUI/customization/res/values-hu/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..32618a869a1fdf75fec6aaa65e988b71deec98e6
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitális, alapértelmezett"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hy/strings.xml b/packages/SystemUI/customization/res/values-hy/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d45afbf256abcbc73e256704480c1e3021a212ae
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hy/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Ô¹Õ¾Õ¡ÕµÕ«Õ¶, Õ¯Õ¡Õ¶Õ­Õ¡Õ¤Ö€Õ¾Õ¡Õ®"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-in/strings.xml b/packages/SystemUI/customization/res/values-in/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6110d5d5b092c5a57081f383a25f2be13da4f35
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-in/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-is/strings.xml b/packages/SystemUI/customization/res/values-is/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5a370d614f0f5676f5cad46227f7c223ce481f27
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-is/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Stafræn, sjálfgefið"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-it/strings.xml b/packages/SystemUI/customization/res/values-it/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2a5087d3066912ed0a8dbc7ea6cfc6801796cf03
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-it/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitale - predefinito"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-iw/strings.xml b/packages/SystemUI/customization/res/values-iw/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ddd28f21ad9974aceb0616b31ef9da4b51abda1c
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-iw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"דיגיטלי ברירת מחדל"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ja/strings.xml b/packages/SystemUI/customization/res/values-ja/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..744604a17efafaad06145bf79d06363be14368cf
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ja/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"デジタル デフォルト"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ka/strings.xml b/packages/SystemUI/customization/res/values-ka/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..88ba1dfc097699fa3293fd0c1a566a604deb06f1
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ka/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ციფრული ნაგულისხმევი"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-kk/strings.xml b/packages/SystemUI/customization/res/values-kk/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9ee6522c49ceba1ec0572c109822af61ee925aa2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-kk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Цифрлық әдепкі"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-km/strings.xml b/packages/SystemUI/customization/res/values-km/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bbc438a69bcd310959b42183c96d75c337697873
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-km/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"លំនាំដើមឌីជីថល"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-kn/strings.xml b/packages/SystemUI/customization/res/values-kn/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e67319d4021b17be80ea941642e223bc1a9caea5
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-kn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ಡಿಜಿಟಲ್ ಡೀಫಾಲ್ಟ್"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ko/strings.xml b/packages/SystemUI/customization/res/values-ko/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fa9103b01e6670865e78490a1c7f2e47eaee50bc
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ko/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"디지털 기본"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ky/strings.xml b/packages/SystemUI/customization/res/values-ky/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..76cc5e211a405da7bd12f197f84ca135026a9219
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ky/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Демейки санариптик"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-lo/strings.xml b/packages/SystemUI/customization/res/values-lo/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..28f50008bd73ad3d24cf9e75ceb3f465973345b0
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-lo/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ດິຈິຕອນຕາມຄ່າເລີ່ມຕົ້ນ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-lt/strings.xml b/packages/SystemUI/customization/res/values-lt/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2fe73154776250043f76e8c4b1487535413ce3f1
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-lt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Skaitmeninis numatytasis"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-lv/strings.xml b/packages/SystemUI/customization/res/values-lv/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e0b904a8a1c974af26006ed3486875e24fc3fd53
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-lv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitālais pulkstenis — noklusējums"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-mk/strings.xml b/packages/SystemUI/customization/res/values-mk/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9b95a6e32b3153f2cd3fcf88ba42b09a3b05c1b4
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-mk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Дигитален стандарден приказ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ml/strings.xml b/packages/SystemUI/customization/res/values-ml/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7f6be8a59904e04492ec4e0b68964317dad64079
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ml/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ഡിജിറ്റൽ ഡിഫോൾട്ട്"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-mn/strings.xml b/packages/SystemUI/customization/res/values-mn/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..38369b6f527d87716390354548109e36e27b5716
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-mn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Дижитал өгөгдмөл"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-mr/strings.xml b/packages/SystemUI/customization/res/values-mr/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..821ff100ab137cda56994009867d004c9e1f588d
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-mr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डीफॉल्टसह क्लॉक फेस"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ms/strings.xml b/packages/SystemUI/customization/res/values-ms/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2f61b47a232409b5fa3d345ab6e7682bfbb586d5
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ms/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital lalai"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-my/strings.xml b/packages/SystemUI/customization/res/values-my/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3d137ebc3abbfeeb2e868e3e61949175aadf87e9
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-my/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ဒစ်ဂျစ်တယ်နာရီ မူရင်း"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-nb/strings.xml b/packages/SystemUI/customization/res/values-nb/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6eb4373c448c6b9f4d0d7fc20761b0e127556a5d
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-nb/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital – standard"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ne/strings.xml b/packages/SystemUI/customization/res/values-ne/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c5b087744a18b5e741dcb3b1a494c5b68be3150f
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ne/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफल्ट"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-nl/strings.xml b/packages/SystemUI/customization/res/values-nl/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4f46ab8b2ba5f853a07ecdbff3e1fb8ed38a886a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-nl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Standaard digitaal"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-or/strings.xml b/packages/SystemUI/customization/res/values-or/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a74017f6b68995756ca61947e968020b936c718c
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-or/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ଡିଜିଟାଲ ଡିଫଲ୍ଟ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-pa/strings.xml b/packages/SystemUI/customization/res/values-pa/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a77661a8f56b85c012deab680a8ea03c15afda1a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-pa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ਡਿਜੀਟਲ ਡਿਫਾਲਟ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-pl/strings.xml b/packages/SystemUI/customization/res/values-pl/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6f5b6f280dd1f61e366e8e6b6913405f5a8e0c15
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-pl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Cyfrowa domyślna"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-pt-rPT/strings.xml b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c6c3cc046965df6f4a6b334773b782853b30e715
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Predefinição digital"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-pt/strings.xml b/packages/SystemUI/customization/res/values-pt/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bbe4355432115638e3a177d9709a82374c54147b
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-pt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital padrão"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ro/strings.xml b/packages/SystemUI/customization/res/values-ro/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ef163e96f79f8fa27fbf569a95f6d37b3cf0c785
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ro/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Implicit digital"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ru/strings.xml b/packages/SystemUI/customization/res/values-ru/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5ee928e0fa37ff5ab9dc28f293f48b19403ba3f2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ru/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Цифровые часы, стандартный"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-si/strings.xml b/packages/SystemUI/customization/res/values-si/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..caf9610e921ede6a42e0bc4eb3de2c351ac6b192
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-si/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ඩිජිටල් පෙරනිමිය"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sk/strings.xml b/packages/SystemUI/customization/res/values-sk/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1843f971d25124d3c811a3faf7388d8ffebf3645
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitálne predvolené"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sl/strings.xml b/packages/SystemUI/customization/res/values-sl/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..12df66f571d3b5f55bbd1c7f4c86c6582fdf3888
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalna (privzeta)"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sq/strings.xml b/packages/SystemUI/customization/res/values-sq/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1fc9f252175f3ff2859375f411b7abb7bb1b0858
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sq/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Dixhitale e parazgjedhur"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sr/strings.xml b/packages/SystemUI/customization/res/values-sr/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6b127c9f79e5d685ca64f4ef3f62c68c5768c3c4
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Дигитални подразумевани"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sv/strings.xml b/packages/SystemUI/customization/res/values-sv/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..84ad25c96655cf6478d26bf17b599f6bd8c7bf77
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital standard"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw/strings.xml b/packages/SystemUI/customization/res/values-sw/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e2ec3de573a82963fa74bbf94da960427a7c75bb
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Dijitali chaguomsingi"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ta/strings.xml b/packages/SystemUI/customization/res/values-ta/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f4eea07b0aa5a5f5ce1a24e98735b53168f6f60a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ta/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"டிஜிட்டல் இயல்பு"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-te/strings.xml b/packages/SystemUI/customization/res/values-te/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c7c77d527e7f53db1906fc547f23e32e1134be06
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-te/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"డిజిటల్ ఆటోమేటిక్ సెట్టింగ్"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-th/strings.xml b/packages/SystemUI/customization/res/values-th/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..61d880eb1ad99975d20669e5b10fe301bffb4e81
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-th/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ดิจิทัลแบบเริ่มต้น"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-tl/strings.xml b/packages/SystemUI/customization/res/values-tl/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a3484a7b6d2a91f57e4c95903b9707eeaef51427
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-tl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital na default"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-tr/strings.xml b/packages/SystemUI/customization/res/values-tr/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a90e9852ef2f94d2d1d8f3a2ccea14b950747d27
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-tr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Dijital varsayılan"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-uk/strings.xml b/packages/SystemUI/customization/res/values-uk/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ee9b77b905a228388ab48ec9734da91d5c6ba7b9
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-uk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Цифровий, стандартний"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ur/strings.xml b/packages/SystemUI/customization/res/values-ur/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..06a6a7cd01fd57fd8b9d1ea796d365b41a959677
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ur/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ڈیجیٹل ڈیفالٹ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-uz/strings.xml b/packages/SystemUI/customization/res/values-uz/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6b31b048b4a1a2d9064303b77d72abe5e3e62de1
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-uz/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Raqamli soat, standart"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-vi/strings.xml b/packages/SystemUI/customization/res/values-vi/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..830b6e2b16a1ef9738b6fdeb82ed950f2e6f130a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-vi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Mặt số mặc định"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-zh-rCN/strings.xml b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..747567e9fb659222cff2102e0da051f76ecc4fa1
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"默认数字"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-zh-rHK/strings.xml b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c19cc68ff15077ba82dff0ca1145512545267e77
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"數碼時鐘 (預設)"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-zh-rTW/strings.xml b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6fcd313a291d03714a715014cd4c212572323682
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"數位預設"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-zu/strings.xml b/packages/SystemUI/customization/res/values-zu/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c87c250ae1b9f4670632e6c9087718e7048e3da7
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-zu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Okuzenzakalelayo kwedijithali"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values/strings.xml b/packages/SystemUI/customization/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..897c842b6d4b099c02e24e04e579045ff8282d4b
--- /dev/null
+++ b/packages/SystemUI/customization/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- default clock face name [CHAR LIMIT=NONE]-->
+    <string name="clock_default_name">Default</string>
+
+    <!-- default clock face description [CHAR LIMIT=NONE]-->
+    <string name="clock_default_description">Digital default</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index b28920c590c5182cebd064fc2e87852392b39a8d..b076b2cacf08326dfa7bd2859b250b071e4ef26b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -65,7 +65,13 @@ class DefaultClockController(
     protected var onSecondaryDisplay: Boolean = false
 
     override val events: DefaultClockEvents
-    override val config = ClockConfig(DEFAULT_CLOCK_ID)
+    override val config: ClockConfig by lazy {
+        ClockConfig(
+            DEFAULT_CLOCK_ID,
+            resources.getString(R.string.clock_default_name),
+            resources.getString(R.string.clock_default_description)
+        )
+    }
 
     init {
         val parent = FrameLayout(ctx)
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 949641a7f75edc2636fefd553c05d9c639250b1b..dd52e39488ac334b8102707994746fe7c4b813ea 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
@@ -25,7 +25,6 @@ import com.android.systemui.plugins.ClockProvider
 import com.android.systemui.plugins.ClockSettings
 
 private val TAG = DefaultClockProvider::class.simpleName
-const val DEFAULT_CLOCK_NAME = "Default Clock"
 const val DEFAULT_CLOCK_ID = "DEFAULT"
 
 /** Provides the default system clock */
@@ -35,8 +34,7 @@ class DefaultClockProvider(
     val resources: Resources,
     val hasStepClockAnimation: Boolean = false
 ) : ClockProvider {
-    override fun getClocks(): List<ClockMetadata> =
-        listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME))
+    override fun getClocks(): List<ClockMetadata> = listOf(ClockMetadata(DEFAULT_CLOCK_ID))
 
     override fun createClock(settings: ClockSettings): ClockController {
         if (settings.clockId != DEFAULT_CLOCK_ID) {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index e2f4793b8f91be31042a11b705ba52530a9e27ae..485c27e161506157479e4f96494ca29ce7487f1d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -192,15 +192,18 @@ enum class ClockTickRate(val value: Int) {
 /** Some data about a clock design */
 data class ClockMetadata(
     val clockId: ClockId,
-    val name: String,
-) {
-    constructor(clockId: ClockId) : this(clockId, clockId) {}
-}
+)
 
 /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
 data class ClockConfig(
     val id: String,
 
+    /** Localized name of the clock */
+    val name: String,
+
+    /** Localized accessibility description for the clock */
+    val description: String,
+
     /** Transition to AOD should move smartspace like large clock instead of small clock */
     val useAlternateSmartspaceAODTransition: Boolean = false,
 
diff --git a/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml b/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml
new file mode 100644
index 0000000000000000000000000000000000000000..218735229a5d1a276fa33737c438cb7e18b3240a
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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.
+  ~
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/alternate_bouncer"
+    android:focusable="true"
+    android:clickable="true"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.systemui.scrim.ScrimView
+        android:id="@+id/alternate_bouncer_scrim"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:importantForAccessibility="no"
+        sysui:ignoreRightInset="true"
+    />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index d4b73a4e3de0704b7320f9209eb43401ab99abfb..acee4258b64d8405c25aca0d7c5878f0b77d569d 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -130,6 +130,11 @@
         android:inflatedId="@+id/multi_shade"
         android:layout="@layout/multi_shade" />
 
+    <include layout="@layout/alternate_bouncer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible" />
+
     <com.android.systemui.biometrics.AuthRippleView
         android:id="@+id/auth_ripple"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 0094820f0dad17880e858ecb1a33814195661161..a6e04cec5f8603a2d7051ac177460c5ce2e58c74 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -23,6 +23,7 @@ import android.view.SurfaceControl;
 import android.window.PictureInPictureSurfaceTransaction;
 import android.window.TaskSnapshot;
 
+import com.android.internal.os.IResultReceiver;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 public class RecentsAnimationControllerCompat {
@@ -89,11 +90,16 @@ public class RecentsAnimationControllerCompat {
      * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous
      *                          app.
      */
-    public void finish(boolean toHome, boolean sendUserLeaveHint) {
+    public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {
         try {
-            mAnimationController.finish(toHome, sendUserLeaveHint);
+            mAnimationController.finish(toHome, sendUserLeaveHint, finishCb);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to finish recents animation", e);
+            try {
+                finishCb.send(0, null);
+            } catch (Exception ex) {
+                // Local call, can ignore
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index c0ee71cf0dc82d4dac8019858429585dbc107659..0dfaf0f4318de03b8070c44a70827e7b2f359c64 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -18,8 +18,15 @@ package com.android.systemui.classifier;
 
 import android.view.MotionEvent;
 
+import javax.inject.Inject;
+
 /** */
 public class FalsingCollectorFake implements FalsingCollector {
+
+    @Inject
+    public FalsingCollectorFake() {
+    }
+
     @Override
     public void onSuccessfulUnlock() {
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index 046ccf165d07b0a02117cdb2d160c3eb562751e6..a90980fddfb0ef73219a37e8159ebf011b1c2950 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -18,7 +18,6 @@ package com.android.systemui.dagger;
 
 import com.android.systemui.globalactions.ShutdownUiModule;
 import com.android.systemui.keyguard.CustomizationProvider;
-import com.android.systemui.shade.ShadeModule;
 import com.android.systemui.statusbar.NotificationInsetsModule;
 import com.android.systemui.statusbar.QsFrameTranslateModule;
 
@@ -33,7 +32,6 @@ import dagger.Subcomponent;
         DependencyProvider.class,
         NotificationInsetsModule.class,
         QsFrameTranslateModule.class,
-        ShadeModule.class,
         ShutdownUiModule.class,
         SystemUIBinder.class,
         SystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 9e5fd5572dbcea8bbcab8ebfc0fec8e2d15d6a99..1dd4abfa076787553a2a630515b2d1691506c537 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -21,12 +21,9 @@ import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
 
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
-import android.os.Handler;
 
-import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardViewController;
 import com.android.systemui.battery.BatterySaverModule;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
@@ -34,7 +31,6 @@ import com.android.systemui.media.dagger.MediaModule;
 import com.android.systemui.navigationbar.NavigationBarControllerModule;
 import com.android.systemui.navigationbar.gestural.GestureModule;
 import com.android.systemui.plugins.qs.QSFactory;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.qs.dagger.QSModule;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
@@ -45,7 +41,7 @@ import com.android.systemui.scene.SceneContainerFrameworkModule;
 import com.android.systemui.screenshot.ReferenceScreenshotModule;
 import com.android.systemui.settings.dagger.MultiUserUtilsModule;
 import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
-import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeModule;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyboardShortcutsModule;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -53,20 +49,13 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;
 import com.android.systemui.statusbar.events.StatusBarEventsModule;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.phone.DozeServiceHost;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.HeadsUpModule;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.AospPolicyModule;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;
 import com.android.systemui.statusbar.policy.SensorPrivacyController;
@@ -100,11 +89,13 @@ import javax.inject.Named;
         BatterySaverModule.class,
         CollapsedStatusBarFragmentStartableModule.class,
         GestureModule.class,
+        HeadsUpModule.class,
         MediaModule.class,
         MultiUserUtilsModule.class,
         NavigationBarControllerModule.class,
         PowerModule.class,
         QSModule.class,
+        ShadeModule.class,
         ReferenceScreenshotModule.class,
         RotationLockModule.class,
         SceneContainerFrameworkModule.class,
@@ -161,38 +152,6 @@ public abstract class ReferenceSystemUIModule {
         return true;
     }
 
-    @SysUISingleton
-    @Provides
-    static HeadsUpManagerPhone provideHeadsUpManagerPhone(
-            Context context,
-            HeadsUpManagerLogger headsUpManagerLogger,
-            StatusBarStateController statusBarStateController,
-            KeyguardBypassController bypassController,
-            GroupMembershipManager groupManager,
-            VisualStabilityProvider visualStabilityProvider,
-            ConfigurationController configurationController,
-            @Main Handler handler,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
-            UiEventLogger uiEventLogger,
-            ShadeExpansionStateManager shadeExpansionStateManager) {
-        return new HeadsUpManagerPhone(
-                context,
-                headsUpManagerLogger,
-                statusBarStateController,
-                bypassController,
-                groupManager,
-                visualStabilityProvider,
-                configurationController,
-                handler,
-                accessibilityManagerWrapper,
-                uiEventLogger,
-                shadeExpansionStateManager
-        );
-    }
-
-    @Binds
-    abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
-
     @Provides
     @SysUISingleton
     static Recents provideRecents(Context context, RecentsImplementation recentsImplementation,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index d89332d6d68671c03179421164a308b5e1214c24..5d6949b3e87f8232da39c105a994e251d43d8d01 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -37,6 +37,7 @@ import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable
 import com.android.systemui.keyguard.KeyguardViewConfigurator
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
+import com.android.systemui.keyguard.ui.binder.AlternateBouncerBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardDismissActionBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardDismissBinder
 import com.android.systemui.log.SessionTracker
@@ -92,6 +93,11 @@ abstract class SystemUICoreStartableModule {
     @ClassKey(AuthController::class)
     abstract fun bindAuthController(service: AuthController): CoreStartable
 
+    @Binds
+    @IntoMap
+    @ClassKey(AlternateBouncerBinder::class)
+    abstract fun bindAlternateBouncerBinder(impl: AlternateBouncerBinder): CoreStartable
+
     /** Inject into BiometricNotificationService */
     @Binds
     @IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d518c0805a34fd53f1822f45c07c2ff3b8d82e04..f6f24e0aecc0f0ef60efa76e1226d85f14ee00f0 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -304,6 +304,11 @@ object Flags {
     @JvmField
     val WALLPAPER_PICKER_PREVIEW_ANIMATION = releasedFlag("wallpaper_picker_preview_animation")
 
+    /** Flag to enable rest to unlock feature. */
+    // TODO(b/303672286): Tracking bug
+    @JvmField
+    val REST_TO_UNLOCK: UnreleasedFlag = unreleasedFlag("rest_to_unlock")
+
     /**
      * TODO(b/278086361): Tracking bug
      * Complete rewrite of the interactions between System UI and Window Manager involving keyguard
@@ -326,7 +331,7 @@ object Flags {
     /** Flag to use a separate view for the alternate bouncer. */
     // TODO(b/300440924): Tracking bug
     @JvmField
-    val ALTERNATE_BOUNCER_REFACTOR: UnreleasedFlag = unreleasedFlag("alternate_bouncer_view")
+    val ALTERNATE_BOUNCER_VIEW: UnreleasedFlag = unreleasedFlag("alternate_bouncer_view")
 
     // 300 - power menu
     // TODO(b/254512600): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 3ccf446fef591de03631c647af4605d935c4740e..d06f31fed8dbdb8d479e8082d9b550e521cbab3c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
 
 @SysUISingleton
 class FromAlternateBouncerTransitionInteractor
@@ -129,11 +130,11 @@ constructor(
     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
         return ValueAnimator().apply {
             interpolator = Interpolators.LINEAR
-            duration = TRANSITION_DURATION_MS
+            duration = TRANSITION_DURATION_MS.inWholeMilliseconds
         }
     }
 
     companion object {
-        private const val TRANSITION_DURATION_MS = 300L
+        val TRANSITION_DURATION_MS = 300.milliseconds
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
index e57c919a5b3ef661a9d15d3ac1bfea4c61f43a7d..89aca7631934699552a326bef6bc7caf1478cf2b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
@@ -61,6 +61,7 @@ interface KeyguardFaceAuthInteractor {
     fun onSwipeUpOnBouncer()
     fun onPrimaryBouncerUserInput()
     fun onAccessibilityAction()
+    fun onWalletLaunched()
 }
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
index 596a1c01ca42fa670c2977193dcc1205706ce615..f38bb2b519e70562873a9b5df26fd3fbc324e56e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
@@ -61,4 +61,5 @@ class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInt
     override fun onSwipeUpOnBouncer() {}
     override fun onPrimaryBouncerUserInput() {}
     override fun onAccessibilityAction() {}
+    override fun onWalletLaunched() = Unit
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index ef1d5ac2a6d4ddcc87c603819bbf11dbc82f3e69..797dec2c96255971d2be89fcfd60fea4c1f8a79a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.CoreStartable
 import com.android.systemui.biometrics.data.repository.FacePropertyRepository
 import com.android.systemui.biometrics.shared.model.LockoutMode
+import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
@@ -33,7 +34,6 @@ import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
 import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -44,6 +44,7 @@ import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.repository.UserRepository
 import com.android.systemui.util.kotlin.pairwise
 import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
@@ -56,7 +57,6 @@ import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.yield
-import javax.inject.Inject
 
 /**
  * Encapsulates business logic related face authentication being triggered for device entry from
@@ -79,7 +79,6 @@ constructor(
     private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     private val userRepository: UserRepository,
     private val facePropertyRepository: FacePropertyRepository,
-    private val keyguardRepository: KeyguardRepository,
     private val faceWakeUpTriggersConfig: FaceWakeUpTriggersConfig,
     private val powerInteractor: PowerInteractor,
 ) : CoreStartable, KeyguardFaceAuthInteractor {
@@ -207,6 +206,12 @@ constructor(
         runFaceAuth(FaceAuthUiEvent.FACE_AUTH_ACCESSIBILITY_ACTION, false)
     }
 
+    override fun onWalletLaunched() {
+        if (facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG) {
+            runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED, true)
+        }
+    }
+
     override fun registerListener(listener: FaceAuthenticationListener) {
         listeners.add(listener)
     }
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
new file mode 100644
index 0000000000000000000000000000000000000000..41af9e810fbf7a17207322ba2693fd55c955a924
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.keyguard.ui.binder
+
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.scrim.ScrimView
+import com.android.systemui.shade.NotificationShadeWindowView
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AlternateBouncerBinder
+@Inject
+constructor(
+    private val notificationShadeWindowView: NotificationShadeWindowView,
+    private val featureFlags: FeatureFlagsClassic,
+    private val alternateBouncerViewModel: AlternateBouncerViewModel,
+    @Application private val scope: CoroutineScope,
+    private val notificationShadeWindowController: NotificationShadeWindowController,
+) : CoreStartable {
+    override fun start() {
+        if (!featureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+            return
+        }
+
+        AlternateBouncerViewBinder.bind(
+            notificationShadeWindowView.requireViewById(R.id.alternate_bouncer),
+            alternateBouncerViewModel,
+            scope,
+            notificationShadeWindowController,
+        )
+    }
+}
+
+/**
+ * Binds the alternate bouncer view to its view-model.
+ *
+ * To use this properly, users should maintain a one-to-one relationship between the [View] and the
+ * view-binding, binding each view only once. It is okay and expected for the same instance of the
+ * view-model to be reused for multiple view/view-binder bindings.
+ */
+@ExperimentalCoroutinesApi
+object AlternateBouncerViewBinder {
+
+    /** Binds the view to the view-model, continuing to update the former based on the latter. */
+    @JvmStatic
+    fun bind(
+        view: ViewGroup,
+        viewModel: AlternateBouncerViewModel,
+        scope: CoroutineScope,
+        notificationShadeWindowController: NotificationShadeWindowController,
+    ) {
+        scope.launch {
+            // forcePluginOpen is necessary to show over occluded apps.
+            // This cannot be tied to the view's lifecycle because setting this allows the view
+            // to be started in the first place.
+            viewModel.forcePluginOpen.collect {
+                notificationShadeWindowController.setForcePluginOpen(it, this)
+            }
+        }
+
+        val scrim = view.requireViewById(R.id.alternate_bouncer_scrim) as ScrimView
+        view.repeatWhenAttached { alternateBouncerViewContainer ->
+            repeatOnLifecycle(Lifecycle.State.STARTED) {
+                scrim.viewAlpha = 0f
+
+                launch {
+                    viewModel.onClickListener.collect {
+                        // TODO (b/287599719): Support swiping to dismiss altBouncer
+                        alternateBouncerViewContainer.setOnClickListener(it)
+                    }
+                }
+
+                launch {
+                    viewModel.scrimAlpha.collect {
+                        alternateBouncerViewContainer.visibility =
+                            if (it < .1f) View.INVISIBLE else View.VISIBLE
+                        scrim.viewAlpha = it
+                    }
+                }
+
+                launch { viewModel.scrimColor.collect { scrim.tint = it } }
+            }
+        }
+    }
+}
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 5ae2abaea7884d0223ed86c40c33ed3f5976557e..c6d8ec7789f27d60778e353aa950bc3d84dccb50 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
@@ -27,11 +27,14 @@ import android.hardware.display.DisplayManager
 import android.os.Bundle
 import android.os.Handler
 import android.os.IBinder
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
 import android.view.LayoutInflater
 import android.view.SurfaceControlViewHost
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD
 import android.widget.FrameLayout
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.isInvisible
@@ -125,6 +128,8 @@ constructor(
     private val shouldHideClock: Boolean =
         bundle.getBoolean(ClockPreviewConstants.KEY_HIDE_CLOCK, false)
     private val wallpaperColors: WallpaperColors? = bundle.getParcelable(KEY_COLORS)
+    private val displayId = bundle.getInt(KEY_DISPLAY_ID, DEFAULT_DISPLAY)
+    private val display: Display = displayManager.getDisplay(displayId)
 
     private var host: SurfaceControlViewHost
 
@@ -164,7 +169,7 @@ constructor(
             host =
                 SurfaceControlViewHost(
                     context,
-                    displayManager.getDisplay(bundle.getInt(KEY_DISPLAY_ID)),
+                    displayManager.getDisplay(DEFAULT_DISPLAY),
                     hostToken,
                     "KeyguardPreviewRenderer"
                 )
@@ -174,21 +179,27 @@ constructor(
 
     fun render() {
         mainHandler.post {
-            val rootView = FrameLayout(context)
+            val previewContext = context.createDisplayContext(display)
 
-            setupKeyguardRootView(rootView)
+            val rootView = FrameLayout(previewContext)
+
+            setupKeyguardRootView(previewContext, rootView)
 
             if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                 setUpBottomArea(rootView)
             }
 
+            val windowContext = context.createWindowContext(display, TYPE_KEYGUARD, null)
+            val windowManagerOfDisplay = windowContext.getSystemService(WindowManager::class.java)
             rootView.measure(
                 View.MeasureSpec.makeMeasureSpec(
-                    windowManager.currentWindowMetrics.bounds.width(),
+                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.width()
+                        ?: windowManager.currentWindowMetrics.bounds.width(),
                     View.MeasureSpec.EXACTLY
                 ),
                 View.MeasureSpec.makeMeasureSpec(
-                    windowManager.currentWindowMetrics.bounds.height(),
+                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.height()
+                        ?: windowManager.currentWindowMetrics.bounds.height(),
                     View.MeasureSpec.EXACTLY
                 ),
             )
@@ -251,7 +262,7 @@ constructor(
      *
      * The end padding is as follows: Below clock padding end
      */
-    private fun setUpSmartspace(parentView: ViewGroup) {
+    private fun setUpSmartspace(previewContext: Context, parentView: ViewGroup) {
         if (
             !lockscreenSmartspaceController.isEnabled() ||
                 !lockscreenSmartspaceController.isDateWeatherDecoupled()
@@ -263,12 +274,12 @@ constructor(
 
         val topPadding: Int =
             KeyguardPreviewSmartspaceViewModel.getLargeClockSmartspaceTopPadding(
-                context.resources,
+                previewContext.resources,
             )
         val startPadding: Int =
-            context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)
+            previewContext.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)
         val endPadding: Int =
-            context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)
+            previewContext.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)
 
         smartSpaceView?.let {
             it.setPaddingRelative(startPadding, topPadding, endPadding, 0)
@@ -308,8 +319,8 @@ constructor(
     }
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    private fun setupKeyguardRootView(rootView: FrameLayout) {
-        val keyguardRootView = KeyguardRootView(context, null).apply { removeAllViews() }
+    private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) {
+        val keyguardRootView = KeyguardRootView(previewContext, null).apply { removeAllViews() }
         disposables.add(
             KeyguardRootViewBinder.bind(
                 keyguardRootView,
@@ -333,10 +344,10 @@ constructor(
             if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                 setupShortcuts(keyguardRootView)
             }
-            setUpUdfps(rootView)
+            setUpUdfps(previewContext, rootView)
 
             if (!shouldHideClock) {
-                setUpClock(rootView)
+                setUpClock(previewContext, rootView)
                 KeyguardPreviewClockViewBinder.bind(
                     largeClockHostView,
                     smallClockHostView,
@@ -344,7 +355,7 @@ constructor(
                 )
             }
 
-            setUpSmartspace(rootView)
+            setUpSmartspace(previewContext, rootView)
             smartSpaceView?.let {
                 KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
             }
@@ -381,7 +392,7 @@ constructor(
         }
     }
 
-    private fun setUpUdfps(parentView: ViewGroup) {
+    private fun setUpUdfps(previewContext: Context, parentView: ViewGroup) {
         val sensorBounds = udfpsOverlayInteractor.udfpsOverlayParams.value.sensorBounds
 
         // If sensorBounds are default rect, then there is no UDFPS
@@ -399,7 +410,7 @@ constructor(
             sensorBounds.bottom
         )
         val finger =
-            LayoutInflater.from(context)
+            LayoutInflater.from(previewContext)
                 .inflate(
                     R.layout.udfps_keyguard_preview,
                     parentView,
@@ -408,12 +419,12 @@ constructor(
         parentView.addView(finger, fingerprintLayoutParams)
     }
 
-    private fun setUpClock(parentView: ViewGroup) {
+    private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
         largeClockHostView =
             if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
                 parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)
             } else {
-                val hostView = FrameLayout(context)
+                val hostView = FrameLayout(previewContext)
                 hostView.layoutParams =
                     FrameLayout.LayoutParams(
                         FrameLayout.LayoutParams.MATCH_PARENT,
@@ -429,7 +440,7 @@ constructor(
                 parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)
             } else {
                 val resources = parentView.resources
-                val hostView = FrameLayout(context)
+                val hostView = FrameLayout(previewContext)
                 val layoutParams =
                     FrameLayout.LayoutParams(
                         FrameLayout.LayoutParams.WRAP_CONTENT,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..235a28d4ebc56caae60f3211dfd7f8c12a9d4fc3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import android.graphics.Color
+import android.view.View
+import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TRANSITION_DURATION_MS
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.wm.shell.animation.Interpolators
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+@ExperimentalCoroutinesApi
+class AlternateBouncerViewModel
+@Inject
+constructor(
+    statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+    transitionInteractor: KeyguardTransitionInteractor,
+    falsingManager: FalsingManager,
+) {
+    // When we're fully transitioned to the AlternateBouncer, the alpha of the scrim should be:
+    private val alternateBouncerScrimAlpha = .66f
+    private val toAlternateBouncerTransition =
+        KeyguardTransitionAnimationFlow(
+                transitionDuration = TRANSITION_DURATION_MS,
+                transitionFlow = transitionInteractor.anyStateToAlternateBouncerTransition,
+            )
+            .createFlow(
+                duration = TRANSITION_DURATION_MS,
+                onStep = { it },
+                onFinish = { 1f },
+                // Reset on cancel
+                onCancel = { 0f },
+                interpolator = Interpolators.FAST_OUT_SLOW_IN,
+            )
+    private val fromAlternateBouncerTransition =
+        KeyguardTransitionAnimationFlow(
+                transitionDuration = TRANSITION_DURATION_MS,
+                transitionFlow = transitionInteractor.transitionStepsFromState(ALTERNATE_BOUNCER),
+            )
+            .createFlow(
+                duration = TRANSITION_DURATION_MS,
+                onStep = { 1f - it },
+                // Reset on cancel
+                onCancel = { 0f },
+                interpolator = Interpolators.FAST_OUT_SLOW_IN,
+            )
+
+    /** Progress to a fully transitioned alternate bouncer. 1f represents fully transitioned. */
+    private val transitionToAlternateBouncerProgress =
+        merge(fromAlternateBouncerTransition, toAlternateBouncerTransition)
+
+    val forcePluginOpen: Flow<Boolean> =
+        transitionToAlternateBouncerProgress.map { it > 0f }.distinctUntilChanged()
+
+    /** An observable for the scrim alpha. */
+    val scrimAlpha = transitionToAlternateBouncerProgress.map { it * alternateBouncerScrimAlpha }
+
+    /** An observable for the scrim color. Change color for easier debugging. */
+    val scrimColor: Flow<Int> = flowOf(Color.BLACK)
+
+    private val clickListener =
+        View.OnClickListener {
+            if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+                statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
+            }
+        }
+
+    val onClickListener: Flow<View.OnClickListener?> =
+        transitionToAlternateBouncerProgress
+            .map {
+                if (it == 1f) {
+                    clickListener
+                } else {
+                    null
+                }
+            }
+            .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
index 54abc5bc695f32f8f693e6dd745d246b6b199730..0b1079f69d6e8afade9ab8dc0bdf440307dd2752 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
@@ -19,13 +19,13 @@ package com.android.systemui.keyguard.ui.viewmodel
 import android.content.Context
 import androidx.annotation.ColorInt
 import com.android.settingslib.Utils.getColorAttrDefaultColor
-import com.android.systemui.res.R
 import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.res.R
 import com.android.wm.shell.animation.Interpolators
 import javax.inject.Inject
 import kotlin.math.roundToInt
@@ -62,7 +62,7 @@ open class UdfpsLockscreenViewModel(
 
     private val toAlternateBouncer: Flow<TransitionViewModel> =
         keyguardInteractor.statusBarState.flatMapLatest { statusBarState ->
-            transitionInteractor.anyStateToAlternateBouncerTransition.map {
+            transitionInteractor.transitionStepsToState(KeyguardState.ALTERNATE_BOUNCER).map {
                 TransitionViewModel(
                     alpha = 1f,
                     scale =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
index 8589ae9305fded47433cd118a7c8f9ac1841e790..68bf88b16ae2a9a658432be109676b59d01fbd70 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
@@ -72,7 +72,7 @@ public class QSFragmentLegacy extends LifecycleFragment implements QS {
 
     @Override
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
-        QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this);
+        QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(getView());
         mQsImpl = mQsImplProvider.get();
         mQsImpl.onComponentCreated(qsFragmentComponent, savedInstanceState);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
index 327e858059f3b4f04be63bbc3ae8afe5f2da1dfc..ce8db789842a799aa6585f57e2cbd5c12b022e87 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.qs.dagger;
 
+import android.view.View;
+
+import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.qs.QSFragmentLegacy;
 
 import dagger.BindsInstance;
@@ -31,6 +34,7 @@ public interface QSFragmentComponent extends QSComponent {
     /** Factory for building a {@link QSFragmentComponent}. */
     @Subcomponent.Factory
     interface Factory {
-        QSFragmentComponent create(@BindsInstance QSFragmentLegacy qsFragment);
+        /** */
+        QSFragmentComponent create(@BindsInstance @RootView View view);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 0c9c24df5e3690a760368e466fb27a64faf55285..0e75b2157a7da70781789e848ca97183a7de887c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -20,34 +20,17 @@ import static com.android.systemui.util.Utils.useCollapsedMediaInLandscape;
 import static com.android.systemui.util.Utils.useQsMediaPlayer;
 
 import android.content.Context;
-import android.view.View;
 
-import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.qs.QSFragmentLegacy;
-
-import javax.inject.Named;
-
-import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 
+import javax.inject.Named;
+
 /**
  * Dagger Module for {@link QSFragmentComponent}.
  */
 @Module(includes = {QSScopeModule.class})
 public  interface QSFragmentModule {
-
-    @Provides
-    @RootView
-    static View provideRootView(QSFragmentLegacy qsFragment) {
-        return qsFragment.getView();
-    }
-
-    /** */
-    @Binds
-    QS bindQS(QSFragmentLegacy qsFragment);
-
     /** */
     @Provides
     @Named(QSScopeModule.QS_USING_MEDIA_PLAYER)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
index c5512c15ccc2205331008106a0662d131ae620c2..4bb8c6e4bb2dc7e243e0b874daa7e3a2872fa483 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
@@ -272,7 +272,6 @@ constructor(
                             // repository
                             launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) }
                         }
-                        Log.d("Fabian", "Finished resolving tiles")
                     }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
index 3927873f8ba8bbd754988d626e2ee953888f5c61..f704894e56e210a19989bfce6ba86744dd3c86f9 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
@@ -42,6 +42,13 @@ sealed class ObservableTransitionState {
          * scene, this value will remain true after the pointer is no longer touching the screen and
          * will be true in any transition created to animate back to the original position.
          */
-        val isUserInputDriven: Boolean,
+        val isInitiatedByUserInput: Boolean,
+
+        /**
+         * Whether user input is currently driving the transition. For example, if a user is
+         * dragging a pointer, this emits true. Once they lift their finger, this emits false while
+         * the transition completes/settles.
+         */
+        val isUserInputOngoing: Flow<Boolean>,
     ) : ObservableTransitionState()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 2f873019349cedd83e746b56cf8aabea7c5ab9b8..393a698bcdb7136f922f9a240dc301875c7dea3a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -132,6 +132,7 @@ open class UserTrackerImpl internal constructor(
         setUserIdInternal(startingUser)
 
         val filter = IntentFilter().apply {
+            addAction(Intent.ACTION_LOCALE_CHANGED)
             addAction(Intent.ACTION_USER_INFO_CHANGED)
             // These get called when a managed profile goes in or out of quiet mode.
             addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
@@ -149,6 +150,7 @@ open class UserTrackerImpl internal constructor(
 
     override fun onReceive(context: Context, intent: Intent) {
         when (intent.action) {
+            Intent.ACTION_LOCALE_CHANGED,
             Intent.ACTION_USER_INFO_CHANGED,
             Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
             Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
index 9235fcc8202f440c320096e5cb8720b2e120b8b1..c42fdf8e7b934c11bcac3cbea205ef3bac2d0499 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
@@ -67,8 +67,6 @@ public class DebugDrawable extends Drawable {
         mDebugPaint.setStrokeWidth(2);
         mDebugPaint.setStyle(Paint.Style.STROKE);
         mDebugPaint.setTextSize(24);
-        String headerDebugInfo = mNotificationPanelViewController.getHeaderDebugInfo();
-        if (headerDebugInfo != null) canvas.drawText(headerDebugInfo, 50, 100, mDebugPaint);
 
         drawDebugInfo(canvas, mNotificationPanelViewController.getMaxPanelHeight(),
                 Color.RED, "getMaxPanelHeight()");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 1c62b6a184fa3088397b402dd2e3c9e5b74baeeb..2ef83dd42868073cdce78ad30b19a1732816a32a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -138,7 +138,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.power.shared.model.WakefulnessModel;
 import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
 import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel;
@@ -162,9 +161,10 @@ import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.power.shared.model.WakefulnessModel;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.data.repository.ShadeRepository;
-import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
@@ -200,7 +200,6 @@ import com.android.systemui.statusbar.phone.BounceInterpolator;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
@@ -217,6 +216,7 @@ import com.android.systemui.statusbar.phone.TapAgainViewController;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
@@ -362,7 +362,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
     private boolean mIsLaunchAnimationRunning;
     private float mOverExpansion;
     private CentralSurfaces mCentralSurfaces;
-    private HeadsUpManagerPhone mHeadsUpManager;
+    private HeadsUpManager mHeadsUpManager;
     private float mExpandedHeight = 0;
     /** The current squish amount for the predictive back animation */
     private float mCurrentBackProgress = 0.0f;
@@ -3026,7 +3026,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
         return headsUpVisible || isExpanded() || mBouncerShowing;
     }
 
-    private void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
+    private void setHeadsUpManager(HeadsUpManager headsUpManager) {
         mHeadsUpManager = headsUpManager;
         mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
         mHeadsUpTouchHelper = new HeadsUpTouchHelper(
@@ -3508,7 +3508,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
             GestureRecorder recorder,
             Runnable hideExpandedRunnable,
             NotificationShelfController notificationShelfController,
-            HeadsUpManagerPhone headsUpManager) {
+            HeadsUpManager headsUpManager) {
         setHeadsUpManager(headsUpManager);
         // TODO(b/254859580): this can be injected.
         mCentralSurfaces = centralSurfaces;
@@ -3557,10 +3557,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
         mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
     }
 
-    String getHeaderDebugInfo() {
-        return "USER " + mHeadsUpManager.getUser();
-    }
-
     @Override
     public void onThemeChanged() {
         mConfigurationListener.onThemeChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 5c5cf7dd679c8417e4c8d3b882a5d6dffd4d2982..5414b3f30aa50eae97aebb94b34cc18d54c99e5c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -37,7 +37,9 @@ import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.back.domain.interactor.BackActionInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
 import com.android.systemui.classifier.FalsingCollector;
@@ -105,6 +107,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
     private final boolean mIsTrackpadCommonEnabled;
     private final FeatureFlags mFeatureFlags;
     private final KeyEventInteractor mKeyEventInteractor;
+    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     private GestureDetector mPulsingWakeupGestureHandler;
     private GestureDetector mDreamingWakeupGestureHandler;
     private View mBrightnessMirror;
@@ -181,7 +185,9 @@ public class NotificationShadeWindowViewController implements Dumpable {
             SystemClock clock,
             BouncerMessageInteractor bouncerMessageInteractor,
             BouncerLogger bouncerLogger,
-            KeyEventInteractor keyEventInteractor) {
+            KeyEventInteractor keyEventInteractor,
+            PrimaryBouncerInteractor primaryBouncerInteractor,
+            AlternateBouncerInteractor alternateBouncerInteractor) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
@@ -209,6 +215,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
         mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
         mFeatureFlags = featureFlags;
         mKeyEventInteractor = keyEventInteractor;
+        mPrimaryBouncerInteractor = primaryBouncerInteractor;
+        mAlternateBouncerInteractor = alternateBouncerInteractor;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -431,8 +439,15 @@ public class NotificationShadeWindowViewController implements Dumpable {
                     return true;
                 }
 
+                boolean bouncerShowing;
+                if (mFeatureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+                    bouncerShowing = mPrimaryBouncerInteractor.isBouncerShowing()
+                            || mAlternateBouncerInteractor.isVisibleState();
+                } else {
+                    bouncerShowing = mService.isBouncerShowing();
+                }
                 if (mNotificationPanelViewController.isFullyExpanded()
-                        && !mService.isBouncerShowing()
+                        && !bouncerShowing
                         && !mStatusBarStateController.isDozing()) {
                     if (mDragDownHelper.isDragDownEnabled()) {
                         // This handles drag down over lockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 447a15d34c05148074195e41be2f69c6604463be..2c4b0b990e6db2f400e5dcddb0eed6c44363d584 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -178,9 +178,6 @@ public interface ShadeController extends CoreStartable {
 
     /** Listens for shade visibility changes. */
     interface ShadeVisibilityListener {
-        /** Called when the visibility of the shade changes. */
-        void visibilityChanged(boolean visible);
-
         /** Called when shade expanded and visible state changed. */
         void expandedVisibleChanged(boolean expandedVisible);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 367449b9d59d8bdc64b5f1fe9d434f77a909b12a..fdc7eecd9b15766589b38477d359bf7d35888718 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -24,6 +24,7 @@ import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
+import com.android.systemui.DejankUtils;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -75,6 +76,7 @@ public final class ShadeControllerImpl implements ShadeController {
     private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
 
     private boolean mExpandedVisible;
+    private boolean mLockscreenOrShadeVisible;
 
     private NotificationPresenter mPresenter;
     private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@@ -399,8 +401,19 @@ public final class ShadeControllerImpl implements ShadeController {
     }
 
     private void notifyVisibilityChanged(boolean visible) {
-        mShadeVisibilityListener.visibilityChanged(visible);
         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(visible);
+        if (mLockscreenOrShadeVisible != visible) {
+            mLockscreenOrShadeVisible = visible;
+            if (visible) {
+                // It would be best if this could be done as a side effect of listening to the
+                // [WindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible] flow inside
+                // NotificationShadeWindowViewController. However, there's no guarantee that the
+                // flow will emit in the same frame as when the visibility changed, and we want the
+                // DejankUtils to be notified immediately, so we do it immediately here.
+                DejankUtils.notifyRendererOfExpensiveFrame(
+                        getNotificationShadeWindowView(), "onShadeVisibilityChanged");
+            }
+        }
     }
 
     private void notifyExpandedVisibleChanged(boolean expandedVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 6ee6cbf69a706010a24cfb8e96eef58f90555269..4e23e7d97a01dd6da72f7161bfbe32b7891fc21f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -20,7 +20,7 @@ import com.android.systemui.statusbar.GestureRecorder
 import com.android.systemui.statusbar.NotificationShelfController
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.HeadsUpManager
 
 /**
  * Allows CentralSurfacesImpl to interact with the shade. Only CentralSurfacesImpl should reference
@@ -34,7 +34,7 @@ interface ShadeSurface : ShadeViewController {
         recorder: GestureRecorder,
         hideExpandedRunnable: Runnable,
         notificationShelfController: NotificationShelfController,
-        headsUpManager: HeadsUpManagerPhone
+        headsUpManager: HeadsUpManager
     )
 
     /** Cancels any pending collapses. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index ac8333ae84adc5d2c23a883c4b6e68a8f06e71e9..6117f9f80e6c4c676545ad3a5134ebbf2c6c8524 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -19,7 +19,11 @@ package com.android.systemui.shade.domain.interactor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.ObservableTransitionState
@@ -27,8 +31,9 @@ import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepository
 import com.android.systemui.user.domain.interactor.UserInteractor
 import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
@@ -56,13 +61,16 @@ class ShadeInteractor
 @Inject
 constructor(
     @Application scope: CoroutineScope,
+    deviceProvisioningRepository: DeviceProvisioningRepository,
     disableFlagsRepository: DisableFlagsRepository,
+    dozeParams: DozeParameters,
     sceneContainerFlags: SceneContainerFlags,
     // TODO(b/300258424) convert to direct reference instead of provider
     sceneInteractorProvider: Provider<SceneInteractor>,
     keyguardRepository: KeyguardRepository,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    powerInteractor: PowerInteractor,
     userSetupRepository: UserSetupRepository,
-    deviceProvisionedController: DeviceProvisionedController,
     userInteractor: UserInteractor,
     sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
     repository: ShadeRepository,
@@ -187,6 +195,26 @@ constructor(
         combine(isUserInteractingWithShade, isUserInteractingWithShade) { shade, qs -> shade || qs }
             .distinctUntilChanged()
 
+    /** Are touches allowed on the notification panel? */
+    val isShadeTouchable: Flow<Boolean> =
+        combine(
+            powerInteractor.isAsleep,
+            keyguardTransitionInteractor.isInTransitionToStateWhere { it == KeyguardState.AOD },
+            keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING },
+            deviceProvisioningRepository.isFactoryResetProtectionActive,
+        ) { isAsleep, goingToSleep, isPulsing, isFrpActive ->
+            when {
+                // Touches are disabled when Factory Reset Protection is active
+                isFrpActive -> false
+                // If the device is going to sleep, only accept touches if we're still
+                // animating
+                goingToSleep -> dozeParams.shouldControlScreenOff()
+                // If the device is asleep, only accept touches if there's a pulse
+                isAsleep -> isPulsing
+                else -> true
+            }
+        }
+
     /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
     val isExpandToQsEnabled: Flow<Boolean> =
         combine(
@@ -194,8 +222,9 @@ constructor(
             isShadeEnabled,
             keyguardRepository.isDozing,
             userSetupRepository.isUserSetupFlow,
-        ) { disableFlags, isShadeEnabled, isDozing, isUserSetup ->
-            deviceProvisionedController.isDeviceProvisioned &&
+            deviceProvisioningRepository.isDeviceProvisioned,
+        ) { disableFlags, isShadeEnabled, isDozing, isUserSetup, isDeviceProvisioned ->
+            isDeviceProvisioned &&
                 // Disallow QS during setup if it's a simple user switcher. (The user intends to
                 // use the lock screen user switcher, QS is not needed.)
                 (isUserSetup || !userInteractor.isSimpleUserSwitcher) &&
@@ -232,7 +261,7 @@ constructor(
                 when (state) {
                     is ObservableTransitionState.Idle -> false
                     is ObservableTransitionState.Transition ->
-                        state.isUserInputDriven &&
+                        state.isInitiatedByUserInput &&
                             (state.toScene == sceneKey || state.fromScene == sceneKey)
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 3640ae06753738ff6255a99bafad2c3db6ac1183..4ea70264b15240c068bfad22595463df80580a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,22 +31,22 @@ import androidx.annotation.VisibleForTesting
 import com.android.app.animation.Interpolators
 import com.android.systemui.Dumpable
 import com.android.systemui.Gefingerpoken
-import com.android.systemui.res.R
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlin.math.max
@@ -63,7 +63,7 @@ constructor(
     context: Context,
     private val wakeUpCoordinator: NotificationWakeUpCoordinator,
     private val bypassController: KeyguardBypassController,
-    private val headsUpManager: HeadsUpManagerPhone,
+    private val headsUpManager: HeadsUpManager,
     private val roundnessManager: NotificationRoundnessManager,
     configurationController: ConfigurationController,
     private val statusBarStateController: StatusBarStateController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index c62546f67f8dde14277c3bcb316693c108fc44f9..756151bd57e0c03ce4b834ce2fe8073e92aa82ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -24,7 +24,7 @@ import com.android.systemui.animation.LaunchAnimator
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.HeadsUpUtil
 import kotlin.math.ceil
 import kotlin.math.max
@@ -35,7 +35,7 @@ private const val TAG = "NotificationLaunchAnimatorController"
 class NotificationLaunchAnimatorControllerProvider(
     private val notificationExpansionRepository: NotificationExpansionRepository,
     private val notificationListContainer: NotificationListContainer,
-    private val headsUpManager: HeadsUpManagerPhone,
+    private val headsUpManager: HeadsUpManager,
     private val jankMonitor: InteractionJankMonitor
 ) {
     @JvmOverloads
@@ -62,7 +62,7 @@ class NotificationLaunchAnimatorControllerProvider(
 class NotificationLaunchAnimatorController(
     private val notificationExpansionRepository: NotificationExpansionRepository,
     private val notificationListContainer: NotificationListContainer,
-    private val headsUpManager: HeadsUpManagerPhone,
+    private val headsUpManager: HeadsUpManager,
     private val notification: ExpandableNotificationRow,
     private val jankMonitor: InteractionJankMonitor,
     private val onFinishAnimationCallback: Runnable?
@@ -152,16 +152,17 @@ class NotificationLaunchAnimatorController(
         }
     }
 
-    private val headsUpNotificationRow: ExpandableNotificationRow? get() {
-        val summaryEntry = notificationEntry.parent?.summary
+    private val headsUpNotificationRow: ExpandableNotificationRow?
+        get() {
+            val summaryEntry = notificationEntry.parent?.summary
 
-        return when {
-            headsUpManager.isAlerting(notificationKey) -> notification
-            summaryEntry == null -> null
-            headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row
-            else -> null
+            return when {
+                headsUpManager.isAlerting(notificationKey) -> notification
+                summaryEntry == null -> null
+                headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row
+                else -> null
+            }
         }
-    }
 
     private fun removeHun(animate: Boolean) {
         val row = headsUpNotificationRow ?: return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 07eb8a00a17874e666dcf4118a409ed04fa39345..2d839704e0b73ad9c0a49a5a44b066457662397a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -37,8 +37,8 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.headsUpEvents
 import com.android.systemui.util.asIndenting
@@ -85,7 +85,7 @@ constructor(
     @Application private val scope: CoroutineScope,
     private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
     private val secureSettings: SecureSettings,
-    private val seenNotifsProvider: SeenNotificationsProviderImpl,
+    private val notificationListInteractor: NotificationListInteractor,
     private val statusBarStateController: StatusBarStateController,
 ) : Coordinator, Dumpable {
 
@@ -351,7 +351,7 @@ constructor(
 
             override fun onCleanup() {
                 logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs)
-                seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs
+                notificationListInteractor.setHasFilteredOutSeenNotifications(hasFilteredAnyNotifs)
                 hasFilteredAnyNotifs = false
             }
         }
@@ -388,8 +388,8 @@ constructor(
     override fun dump(pw: PrintWriter, args: Array<out String>) =
         with(pw.asIndenting()) {
             println(
-                "seenNotifsProvider.hasFilteredOutSeenNotifications=" +
-                    seenNotifsProvider.hasFilteredOutSeenNotifications
+                "notificationListInteractor.hasFilteredOutSeenNotifications.value=" +
+                    notificationListInteractor.hasFilteredOutSeenNotifications.value
             )
             println("unseen notifications:")
             indentIfPossible {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 657c394d4e309e963d4af50094aa41dee71f03fe..c0f6748469919a2ea46ba2f49afb4c737b92f4f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -28,6 +28,7 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.Compile
+import com.android.systemui.util.traceSection
 import javax.inject.Inject
 
 /**
@@ -122,8 +123,10 @@ class ViewConfigCoordinator @Inject internal constructor(
 
     private fun updateNotificationsOnUiModeChanged() {
         log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
-        mPipeline?.allNotifs?.forEach { entry ->
-            entry.row?.onUiModeChanged()
+        traceSection("updateNotifOnUiModeChanged") {
+            mPipeline?.allNotifs?.forEach { entry ->
+                entry.row?.onUiModeChanged()
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt
deleted file mode 100644
index cff47e22029919ab302b08b29985f8b0d0e3220a..0000000000000000000000000000000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt
+++ /dev/null
@@ -1,41 +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.statusbar.notification.collection.provider
-
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Binds
-import dagger.Module
-import javax.inject.Inject
-
-/** Keeps track of whether "seen" notification content has been filtered out of the shade. */
-interface SeenNotificationsProvider {
-    /** Are any already-seen notifications currently filtered out of the shade? */
-    val hasFilteredOutSeenNotifications: Boolean
-}
-
-@Module
-interface SeenNotificationsProviderModule {
-    @Binds
-    fun bindSeenNotificationsProvider(
-        impl: SeenNotificationsProviderImpl
-    ): SeenNotificationsProvider
-}
-
-@SysUISingleton
-class SeenNotificationsProviderImpl @Inject constructor() : SeenNotificationsProvider {
-    override var hasFilteredOutSeenNotifications: Boolean = false
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 59fc387c4608f0cdcb51f6d219521f1e9f9aa398..1a88815acfafbabf27280e583b98d3f9aed37094 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -231,18 +231,24 @@ private class ShadeNode(val controller: NodeController) {
     fun getChildCount(): Int = controller.getChildCount()
 
     fun addChildAt(child: ShadeNode, index: Int) {
-        controller.addChildAt(child.controller, index)
-        child.controller.onViewAdded()
+        traceSection("ShadeNode#addChildAt") {
+            controller.addChildAt(child.controller, index)
+            child.controller.onViewAdded()
+        }
     }
 
     fun moveChildTo(child: ShadeNode, index: Int) {
-        controller.moveChildTo(child.controller, index)
-        child.controller.onViewMoved()
+        traceSection("ShadeNode#moveChildTo") {
+            controller.moveChildTo(child.controller, index)
+            child.controller.onViewMoved()
+        }
     }
 
     fun removeChild(child: ShadeNode, isTransfer: Boolean) {
-        controller.removeChild(child.controller, isTransfer)
-        child.controller.onViewRemoved()
+        traceSection("ShadeNode#removeChild") {
+            controller.removeChild(child.controller, isTransfer)
+            child.controller.onViewRemoved()
+        }
     }
 
     fun offerToKeepInParentForAnimation(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 8ee0de691557e211bc5b59d9f15fee930d58d7bc..733d774f8b80001ee356beedf4e16dfb2c9148e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -20,10 +20,10 @@ import android.content.Context;
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.shade.ShadeEventsModule;
 import com.android.systemui.statusbar.NotificationListener;
@@ -45,7 +45,6 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Co
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProviderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl;
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderModule;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
@@ -74,9 +73,9 @@ import com.android.systemui.statusbar.notification.stack.NotificationSectionsMan
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
 import dagger.Binds;
@@ -95,7 +94,6 @@ import javax.inject.Provider;
 @Module(includes = {
         CoordinatorsModule.class,
         KeyguardNotificationVisibilityProviderModule.class,
-        SeenNotificationsProviderModule.class,
         ShadeEventsModule.class,
         NotifPipelineChoreographerModule.class,
         NotificationSectionHeadersModule.class,
@@ -206,7 +204,7 @@ public interface NotificationsModule {
     static NotificationLaunchAnimatorControllerProvider provideNotifLaunchAnimControllerProvider(
             NotificationExpansionRepository notificationExpansionRepository,
             NotificationListContainer notificationListContainer,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             InteractionJankMonitor jankMonitor) {
         return new NotificationLaunchAnimatorControllerProvider(
                 notificationExpansionRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
index 5cc5e751ca8ed007ef6f923991ac8805cd65c9df..a77e67b6908d6e36f5747424c181c3f3b09da92c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -118,7 +118,6 @@ constructor(
     private var aodIcons: NotificationIconContainer? = null
     private var aodBindJob: DisposableHandle? = null
     private var aodIconAppearTranslation = 0
-    private var animationsEnabled = false
     private var aodIconTint = 0
     private var aodIconsVisible = false
     private var showLowPriority = true
@@ -157,9 +156,12 @@ constructor(
         }
         this.aodIcons = aodIcons
         this.aodIcons!!.setOnLockScreen(true)
-        aodBindJob = NotificationIconContainerViewBinder.bind(aodIcons, aodIconsViewModel)
+        aodBindJob =
+            NotificationIconContainerViewBinder.bind(
+                aodIcons,
+                aodIconsViewModel,
+            )
         updateAodIconsVisibility(animate = false, forceUpdate = changed)
-        updateAnimations()
         if (changed) {
             updateAodNotificationIcons()
         }
@@ -171,7 +173,10 @@ constructor(
 
     override fun setShelfIcons(icons: NotificationIconContainer) {
         if (shelfRefactor.expectEnabled()) {
-            NotificationIconContainerViewBinder.bind(icons, shelfIconsViewModel)
+            NotificationIconContainerViewBinder.bind(
+                icons,
+                shelfIconsViewModel,
+            )
             shelfIcons = icons
         }
     }
@@ -252,14 +257,10 @@ constructor(
         aodIcons!!.setDozing(isDozing, animate, 0)
     }
 
-    override fun setAnimationsEnabled(enabled: Boolean) {
-        animationsEnabled = enabled
-        updateAnimations()
-    }
+    override fun setAnimationsEnabled(enabled: Boolean) = unsupported
 
     override fun onStateChanged(newState: Int) {
         updateAodIconsVisibility(animate = false, forceUpdate = false)
-        updateAnimations()
     }
 
     override fun onThemeChanged() {
@@ -348,7 +349,10 @@ constructor(
         val layoutInflater = LayoutInflater.from(context)
         notificationIconArea = inflateIconArea(layoutInflater)
         notificationIcons = notificationIconArea?.findViewById(R.id.notificationIcons)
-        NotificationIconContainerViewBinder.bind(notificationIcons!!, statusBarIconsViewModel)
+        NotificationIconContainerViewBinder.bind(
+            notificationIcons!!,
+            statusBarIconsViewModel,
+        )
     }
 
     private fun updateIconLayoutParams(context: Context) {
@@ -598,14 +602,6 @@ constructor(
         v.setDecorColor(tint)
     }
 
-    private fun updateAnimations() {
-        val inShade = statusBarStateController.state == StatusBarState.SHADE
-        if (aodIcons != null) {
-            aodIcons!!.setAnimationsEnabled(animationsEnabled && !inShade)
-        }
-        notificationIcons!!.setAnimationsEnabled(animationsEnabled && inShade)
-    }
-
     private fun animateInAodIconTranslation() {
         if (!statusViewMigrated) {
             aodIcons!!
@@ -702,7 +698,12 @@ constructor(
 
     companion object {
         private const val AOD_ICONS_APPEAR_DURATION: Long = 200
-
         @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1
+
+        val unsupported: Nothing
+            get() =
+                error(
+                    "Code path not supported when NOTIFICATION_ICON_CONTAINER_REFACTOR is disabled"
+                )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 8293bb329a018239523a5922ae2152cac39d61c7..f8ff3e393033cf14140c3c8b8205db01b7801e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -21,6 +21,7 @@ import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel
 import com.android.systemui.statusbar.phone.NotificationIconContainer
 import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.launch
 
 /** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */
 object NotificationIconContainerViewBinder {
@@ -28,6 +29,10 @@ object NotificationIconContainerViewBinder {
         view: NotificationIconContainer,
         viewModel: NotificationIconContainerViewModel,
     ): DisposableHandle {
-        return view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) {} }
+        return view.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.CREATED) {
+                launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) }
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
index f68b0ef7963842ef18c4814707fd7ef621706af1..90507fc82a79084c4553b4e6a86b70c23de5ba24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
@@ -15,8 +15,24 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
 
 /** View-model for the row of notification icons displayed on the always-on display. */
-class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor() :
-    NotificationIconContainerViewModel
+class NotificationIconContainerAlwaysOnDisplayViewModel
+@Inject
+constructor(
+    keyguardInteractor: KeyguardInteractor,
+    shadeInteractor: ShadeInteractor,
+) : NotificationIconContainerViewModel {
+    override val animationsEnabled: Flow<Boolean> =
+        combine(
+            shadeInteractor.isShadeTouchable,
+            keyguardInteractor.isKeyguardVisible,
+        ) { panelTouchesEnabled, isKeyguardVisible ->
+            panelTouchesEnabled && isKeyguardVisible
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
index 933c76f19aee72f11cc6450ad268bd14d256c310..49f262de8f4a2dd932f16484746acff3b77a82f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
@@ -16,7 +16,11 @@
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
 import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
 
 /** View-model for the overflow row of notification icons displayed in the notification shade. */
 class NotificationIconContainerShelfViewModel @Inject constructor() :
-    NotificationIconContainerViewModel
+    NotificationIconContainerViewModel {
+    override val animationsEnabled: Flow<Boolean> = flowOf(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index 2217646e60224d8cba141e0a92ac7953221e69ef..ee57b780b8c37443c8355180c2e12d8983feb455 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -15,8 +15,24 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
 
 /** View-model for the row of notification icons displayed in the status bar, */
-class NotificationIconContainerStatusBarViewModel @Inject constructor() :
-    NotificationIconContainerViewModel
+class NotificationIconContainerStatusBarViewModel
+@Inject
+constructor(
+    keyguardInteractor: KeyguardInteractor,
+    shadeInteractor: ShadeInteractor,
+) : NotificationIconContainerViewModel {
+    override val animationsEnabled: Flow<Boolean> =
+        combine(
+            shadeInteractor.isShadeTouchable,
+            keyguardInteractor.isKeyguardShowing,
+        ) { panelTouchesEnabled, isKeyguardShowing ->
+            panelTouchesEnabled && !isKeyguardShowing
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
index 892b2be9ed6e65c1b1c074ad49e31bae56f90f55..6f8ce4b1db4b4b01ae219bc9adeb260baf70314c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
@@ -15,8 +15,13 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import kotlinx.coroutines.flow.Flow
+
 /**
  * View-model for the row of notification icons displayed in the NotificationShelf, StatusBar, and
  * AOD.
  */
-interface NotificationIconContainerViewModel
+interface NotificationIconContainerViewModel {
+    /** Are changes to the icon container animated? */
+    val animationsEnabled: Flow<Boolean>
+}
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 c61258b5e0ec4131d8b6229ec1b8e422f3c9ed0e..847d94861401caa7ccbcc19af4e592930b6a5969 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
@@ -355,12 +355,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
             AnimatorListenerAdapter animationListener) {
         enableAppearDrawing(true);
         mIsHeadsUpAnimation = isHeadsUpAnimation;
-        if (mDrawingAppearAnimation) {
-            startAppearAnimation(false /* isAppearing */, translationDirection,
-                    delay, duration, onFinishedRunnable, animationListener);
-        } else if (onFinishedRunnable != null) {
-            onFinishedRunnable.run();
-        }
+        startAppearAnimation(false /* isAppearing */, translationDirection,
+                delay, duration, onFinishedRunnable, animationListener);
         return 0;
     }
 
@@ -369,10 +365,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
             Runnable onFinishRunnable) {
         enableAppearDrawing(true);
         mIsHeadsUpAnimation = isHeadsUpAppear;
-        if (mDrawingAppearAnimation) {
-            startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
-                    duration, null, null);
-        }
+        startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
+                duration, null, null);
     }
 
     private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 6d6566058aed75cfd96557d4258ba8543e9ba17b..dc318a392ed5e78b736e066953b16923c043b84d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -46,7 +46,6 @@ import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.notification.ConversationIconFactory;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -54,6 +53,7 @@ import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.shade.ShadeController;
@@ -69,8 +69,8 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi
 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.wmshell.BubblesManager;
 
@@ -127,7 +127,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
     private final ShadeController mShadeController;
     private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
     private NotifGutsViewListener mGutsListener;
-    private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+    private final HeadsUpManager mHeadsUpManager;
     private final ActivityStarter mActivityStarter;
 
     @Inject
@@ -154,7 +154,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
             StatusBarStateController statusBarStateController,
             DeviceProvisionedController deviceProvisionedController,
             MetricsLogger metricsLogger,
-            HeadsUpManagerPhone headsUpManagerPhone,
+            HeadsUpManager headsUpManager,
             ActivityStarter activityStarter) {
         mContext = context;
         mMainHandler = mainHandler;
@@ -179,7 +179,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
         mStatusBarStateController = statusBarStateController;
         mDeviceProvisionedController = deviceProvisionedController;
         mMetricsLogger = metricsLogger;
-        mHeadsUpManagerPhone = headsUpManagerPhone;
+        mHeadsUpManager = headsUpManager;
         mActivityStarter = activityStarter;
     }
 
@@ -296,7 +296,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
             if (mGutsListener != null) {
                 mGutsListener.onGutsClose(entry);
             }
-            mHeadsUpManagerPhone.setGutsShown(row.getEntry(), false);
+            mHeadsUpManager.setGutsShown(row.getEntry(), false);
         });
 
         View gutsView = item.getGutsView();
@@ -676,7 +676,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
                 row.closeRemoteInput();
                 mListContainer.onHeightChanged(row, true /* needsAnimation */);
                 mGutsMenuItem = menuItem;
-                mHeadsUpManagerPhone.setGutsShown(row.getEntry(), true);
+                mHeadsUpManager.setGutsShown(row.getEntry(), true);
             }
         };
         guts.post(mOpenRunnable);
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 66b2555a4446939afb154953ad1aec26fcb6b67a..9695cb132ba9c7b9eb37de506850e6bdf653e93f 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
@@ -99,7 +99,6 @@ import com.android.systemui.statusbar.notification.collection.PipelineDumper;
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController;
@@ -115,10 +114,10 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.NotificationGuts;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationSnooze;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor;
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -127,6 +126,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -156,7 +156,7 @@ public class NotificationStackScrollLayoutController {
     private final NotificationGutsManager mNotificationGutsManager;
     private final NotificationsController mNotificationsController;
     private final NotificationVisibilityProvider mVisibilityProvider;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotificationRoundnessManager mNotificationRoundnessManager;
     private final TunerService mTunerService;
     private final DeviceProvisionedController mDeviceProvisionedController;
@@ -194,7 +194,7 @@ public class NotificationStackScrollLayoutController {
 
     private final GroupExpansionManager mGroupExpansionManager;
     private final NotifPipelineFlags mNotifPipelineFlags;
-    private final SeenNotificationsProvider mSeenNotificationsProvider;
+    private final NotificationListInteractor mNotificationListInteractor;
     private final KeyguardTransitionRepository mKeyguardTransitionRepo;
 
     private NotificationStackScrollLayout mView;
@@ -631,7 +631,7 @@ public class NotificationStackScrollLayoutController {
             NotificationGutsManager notificationGutsManager,
             NotificationsController notificationsController,
             NotificationVisibilityProvider visibilityProvider,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             NotificationRoundnessManager notificationRoundnessManager,
             TunerService tunerService,
             DeviceProvisionedController deviceProvisionedController,
@@ -662,7 +662,7 @@ public class NotificationStackScrollLayoutController {
             UiEventLogger uiEventLogger,
             NotificationRemoteInputManager remoteInputManager,
             VisibilityLocationProviderDelegator visibilityLocationProviderDelegator,
-            SeenNotificationsProvider seenNotificationsProvider,
+            NotificationListInteractor notificationListInteractor,
             ShadeController shadeController,
             InteractionJankMonitor jankMonitor,
             StackStateLogger stackLogger,
@@ -715,7 +715,7 @@ public class NotificationStackScrollLayoutController {
         mUiEventLogger = uiEventLogger;
         mRemoteInputManager = remoteInputManager;
         mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator;
-        mSeenNotificationsProvider = seenNotificationsProvider;
+        mNotificationListInteractor = notificationListInteractor;
         mShadeController = shadeController;
         mNotifIconAreaController = notifIconAreaController;
         mFeatureFlags = featureFlags;
@@ -2006,7 +2006,7 @@ public class NotificationStackScrollLayoutController {
         public void setNotifStats(@NonNull NotifStats notifStats) {
             mNotifStats = notifStats;
             mView.setHasFilteredOutSeenNotifications(
-                    mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
+                    mNotificationListInteractor.getHasFilteredOutSeenNotifications().getValue());
             updateFooter();
             updateShowEmptyShadeView();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f6ed8c884816aed3881d8de7464bc904986dc63b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.statusbar.notification.stack.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** Repository for information about the current notification list. */
+@SysUISingleton
+class NotificationListRepository @Inject constructor() {
+    private val _hasFilteredOutSeenNotifications = MutableStateFlow(false)
+    val hasFilteredOutSeenNotifications: StateFlow<Boolean> =
+        _hasFilteredOutSeenNotifications.asStateFlow()
+
+    fun setHasFilteredOutSeenNotifications(value: Boolean) {
+        _hasFilteredOutSeenNotifications.value = value
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3fd68a8bdd7c3283bf9214a2d77c69d69a9eeb43
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interactor for business logic associated with the notification stack. */
+@SysUISingleton
+class NotificationListInteractor
+@Inject
+constructor(
+    private val notificationListRepository: NotificationListRepository,
+) {
+    /** Are any already-seen notifications currently filtered out of the shade? */
+    val hasFilteredOutSeenNotifications: StateFlow<Boolean>
+        get() = notificationListRepository.hasFilteredOutSeenNotifications
+
+    fun setHasFilteredOutSeenNotifications(value: Boolean) {
+        notificationListRepository.setHasFilteredOutSeenNotifications(value)
+    }
+}
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 3e2f10dd1a0cc29d6d67cfce0f912d9e33cf4596..6e6318e780dcb619de37eb688d802afdd765b101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -220,6 +220,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController.Configurati
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
+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.policy.UserSwitcherController;
@@ -236,6 +237,8 @@ import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
 import com.android.wm.shell.startingsurface.StartingSurface;
 
+import dagger.Lazy;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.List;
@@ -247,8 +250,6 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Provider;
 
-import dagger.Lazy;
-
 /**
  * A class handling initialization and coordination between some of the key central surfaces in
  * System UI: The notification shade, the keyguard (lockscreen), and the status bar.
@@ -417,7 +418,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     private final KeyguardBypassController mKeyguardBypassController;
     private final KeyguardStateController mKeyguardStateController;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
     private final FalsingCollector mFalsingCollector;
     private final FalsingManager mFalsingManager;
@@ -611,7 +612,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
             KeyguardStateController keyguardStateController,
-            HeadsUpManagerPhone headsUpManagerPhone,
+            HeadsUpManager headsUpManager,
             DynamicPrivacyController dynamicPrivacyController,
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
@@ -718,7 +719,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
         mWakeUpCoordinator = notificationWakeUpCoordinator;
         mKeyguardBypassController = keyguardBypassController;
         mKeyguardStateController = keyguardStateController;
-        mHeadsUpManager = headsUpManagerPhone;
+        mHeadsUpManager = headsUpManager;
         mBackActionInteractor = backActionInteractor;
         mKeyguardIndicationController = keyguardIndicationController;
         mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
@@ -1087,11 +1088,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
      */    @VisibleForTesting
     void initShadeVisibilityListener() {
         mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {
-            @Override
-            public void visibilityChanged(boolean visible) {
-                onShadeVisibilityChanged(visible);
-            }
-
             @Override
             public void expandedVisibleChanged(boolean expandedVisible) {
                 if (expandedVisible) {
@@ -1195,7 +1191,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
                 });
         mStatusBarInitializer.initializeStatusBar();
 
-        mStatusBarTouchableRegionManager.setup(this, getNotificationShadeWindowView());
+        mStatusBarTouchableRegionManager.setup(getNotificationShadeWindowView());
 
         createNavigationBar(result);
 
@@ -2688,7 +2684,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
                 !mDozeServiceHost.isPulsing(), mDeviceProvisionedController.isFrpActive());
 
         mShadeSurface.setTouchAndAnimationDisabled(disabled);
-        mNotificationIconAreaController.setAnimationsEnabled(!disabled);
+        if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mNotificationIconAreaController.setAnimationsEnabled(!disabled);
+        }
     }
 
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@@ -2844,13 +2842,16 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
         mScrimController.setExpansionAffectsAlpha(!unlocking);
 
         if (mAlternateBouncerInteractor.isVisibleState()) {
-            if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
-                    && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
-                    || mTransitionToFullShadeProgress > 0f)) {
-                mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
-            } else {
-                mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
+            if (!mFeatureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+                if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
+                        && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
+                        || mTransitionToFullShadeProgress > 0f)) {
+                    mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
+                } else {
+                    mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
+                }
             }
+
             // 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.
             mUnlockScrimCallback.onCancelled();
@@ -2913,8 +2914,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
 
     protected boolean mDeviceInteractive;
 
-    protected boolean mVisible;
-
     protected DevicePolicyManager mDevicePolicyManager;
     private final PowerManager mPowerManager;
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -3032,16 +3031,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
                 afterKeyguardGone);
     }
 
-    private void onShadeVisibilityChanged(boolean visible) {
-        if (mVisible != visible) {
-            mVisible = visible;
-            if (visible) {
-                DejankUtils.notifyRendererOfExpensiveFrame(
-                        getNotificationShadeWindowView(), "onShadeVisibilityChanged");
-            }
-        }
-    }
-
     private void clearNotificationEffects() {
         try {
             mBarService.clearNotificationEffects();
@@ -3163,7 +3152,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
             // TODO: Bring these out of CentralSurfaces.
             mUserInfoControllerImpl.onDensityOrFontScaleChanged();
             mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
-            mHeadsUpManager.onDensityOrFontScaleChanged();
         }
 
         @Override
@@ -3200,7 +3188,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
                     // down on the lockscreen), clear notification LED, vibration,
                     // ringing.
                     // Other transitions are covered in WindowRootViewVisibilityInteractor.
-                    if (mVisible && (newState == StatusBarState.SHADE_LOCKED
+                    if (mWindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible().getValue()
+                            && (newState == StatusBarState.SHADE_LOCKED
                             || mStatusBarStateController.goingToFullShade())) {
                         clearNotificationEffects();
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 4849f64659d070e6db03783b46903ed7e5d49f81..d3d11ea4a9f38513f45456f5e6e6eaaafdcd6ca8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -49,6 +49,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.Assert;
 
@@ -80,7 +81,7 @@ public final class DozeServiceHost implements DozeHost {
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
-    private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+    private final HeadsUpManager mHeadsUpManager;
     private final BatteryController mBatteryController;
     private final ScrimController mScrimController;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@@ -106,7 +107,7 @@ public final class DozeServiceHost implements DozeHost {
             WakefulnessLifecycle wakefulnessLifecycle,
             SysuiStatusBarStateController statusBarStateController,
             DeviceProvisionedController deviceProvisionedController,
-            HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController,
+            HeadsUpManager headsUpManager, BatteryController batteryController,
             ScrimController scrimController,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             Lazy<AssistManager> assistManagerLazy,
@@ -123,7 +124,7 @@ public final class DozeServiceHost implements DozeHost {
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mStatusBarStateController = statusBarStateController;
         mDeviceProvisionedController = deviceProvisionedController;
-        mHeadsUpManagerPhone = headsUpManagerPhone;
+        mHeadsUpManager = headsUpManager;
         mBatteryController = batteryController;
         mScrimController = scrimController;
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
@@ -135,7 +136,7 @@ public final class DozeServiceHost implements DozeHost {
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
         mAuthController = authController;
         mNotificationIconAreaController = notificationIconAreaController;
-        mHeadsUpManagerPhone.addListener(mOnHeadsUpChangedListener);
+        mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
         mDozeInteractor = dozeInteractor;
     }
 
@@ -337,8 +338,8 @@ public final class DozeServiceHost implements DozeHost {
         if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) {
             mScrimController.setWakeLockScreenSensorActive(true);
         }
-        if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) {
-            mHeadsUpManagerPhone.extendHeadsUp();
+        if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) {
+            mHeadsUpManager.extendHeadsUp();
         } else {
             mDozeScrimController.extendPulse();
         }
@@ -493,7 +494,7 @@ public final class DozeServiceHost implements DozeHost {
                     mDozeScrimController.cancelPendingPulseTimeout();
                 }
             }
-            if (!isHeadsUp && !mHeadsUpManagerPhone.hasNotifications()) {
+            if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
                 // There are no longer any notifications to show.  We should end the
                 // pulse now.
                 stopPulsing();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 270c40e801cda76604a3e0fcae6403025b651584..c493eeda707733945b1968a1a46e816eeb7f1b92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -26,9 +26,9 @@ import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeHeadsUpTracker;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationRoundnessMa
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.ViewController;
@@ -70,7 +71,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
     private static final SourceType HEADS_UP = SourceType.from("HeadsUp");
     private static final SourceType PULSING = SourceType.from("Pulsing");
     private final NotificationIconAreaController mNotificationIconAreaController;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotificationStackScrollLayoutController mStackScrollerController;
 
     private final DarkIconDispatcher mDarkIconDispatcher;
@@ -108,7 +109,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
     @Inject
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             StatusBarStateController stateController,
             PhoneStatusBarTransitions phoneStatusBarTransitions,
             KeyguardBypassController bypassController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index a5ea1426164bce1d4eac1acab6dedc60b55d2e03..6b4382f731eab9cbd18f22a622ff2f51cd114004 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -29,11 +29,11 @@ import androidx.collection.ArraySet;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -42,10 +42,12 @@ import com.android.systemui.statusbar.notification.collection.provider.VisualSta
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.AnimationStateHandler;
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -53,11 +55,11 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Stack;
 
-/**
- * A implementation of HeadsUpManager for phone and car.
- */
-public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
-        OnHeadsUpChangedListener {
+import javax.inject.Inject;
+
+/** A implementation of HeadsUpManager for phone. */
+@SysUISingleton
+public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUpChangedListener {
     private static final String TAG = "HeadsUpManagerPhone";
 
     @VisibleForTesting
@@ -102,7 +104,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Constructor:
-
+    @Inject
     public HeadsUpManagerPhone(@NonNull final Context context,
             HeadsUpManagerLogger logger,
             StatusBarStateController statusBarStateController,
@@ -154,7 +156,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
     /**
      * Add a listener to receive callbacks onHeadsUpGoingAway
      */
-    void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
+    @Override
+    public void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
         mHeadsUpPhoneListeners.add(listener);
     }
 
@@ -162,7 +165,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
      * Gets the touchable region needed for heads up notifications. Returns null if no touchable
      * region is required (ie: no heads up notification currently exists).
      */
-    @Nullable Region getTouchableRegion() {
+    @Override
+    public @Nullable Region getTouchableRegion() {
         NotificationEntry topEntry = getTopEntry();
 
         // This call could be made in an inconsistent state while the pinnedMode hasn't been
@@ -197,8 +201,9 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
      * @param key the key of the touched notification
      * @return whether the touch is invalid and should be discarded
      */
-    boolean shouldSwallowClick(@NonNull String key) {
-        HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
+    @Override
+    public boolean shouldSwallowClick(@NonNull String key) {
+        BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
         return entry != null && mClock.currentTimeMillis() < entry.mPostTime;
     }
 
@@ -238,7 +243,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
      * Set that we are exiting the headsUp pinned mode, but some notifications might still be
      * animating out. This is used to keep the touchable regions in a reasonable state.
      */
-    void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+    @Override
+    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
         if (headsUpGoingAway != mHeadsUpGoingAway) {
             mHeadsUpGoingAway = headsUpGoingAway;
             for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
@@ -247,7 +253,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         }
     }
 
-    boolean isHeadsUpGoingAway() {
+    @Override
+    public boolean isHeadsUpGoingAway() {
         return mHeadsUpGoingAway;
     }
 
@@ -260,8 +267,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
     public void setRemoteInputActive(
             @NonNull NotificationEntry entry, boolean remoteInputActive) {
         HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.getKey());
-        if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
-            headsUpEntry.remoteInputActive = remoteInputActive;
+        if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) {
+            headsUpEntry.mRemoteInputActive = remoteInputActive;
             if (remoteInputActive) {
                 headsUpEntry.removeAutoRemovalCallbacks("setRemoteInputActive(true)");
             } else {
@@ -313,6 +320,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         mSwipedOutKeys.add(key);
     }
 
+    @Override
     public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
             boolean animate) {
         if (animate) {
@@ -411,7 +419,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  HeadsUpEntryPhone:
 
-    protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry {
+    protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry {
 
         private boolean mGutsShownPinned;
 
@@ -459,11 +467,11 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
 
         @Override
         public void setExpanded(boolean expanded) {
-            if (this.expanded == expanded) {
+            if (this.mExpanded == expanded) {
                 return;
             }
 
-            this.expanded = expanded;
+            this.mExpanded = expanded;
             if (expanded) {
                 removeAutoRemovalCallbacks("setExpanded(true)");
             } else {
@@ -504,21 +512,6 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         }
     }
 
-    public interface AnimationStateHandler {
-        void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed);
-    }
-
-    /**
-     * Listener to register for HeadsUpNotification Phone changes.
-     */
-    public interface OnHeadsUpPhoneListenerChange {
-        /**
-         * Called when a heads up notification is 'going away' or no longer 'going away'.
-         * See {@link HeadsUpManagerPhone#setHeadsUpGoingAway}.
-         */
-        void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway);
-    }
-
     private final StateListener mStatusBarStateListener = new StateListener() {
         @Override
         public void onStateChanged(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0d0f2cd50a298f15d10e9c45ae58b98526c9abbf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
@@ -0,0 +1,11 @@
+package com.android.systemui.statusbar.phone
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface HeadsUpModule {
+    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: HeadsUpManagerPhone): HeadsUpManager
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index dcbaac20eaccadfae3b6155daebd0e1480c19a4e..198272e9b162963d824ec76963612432db538442 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -26,13 +26,14 @@ import com.android.systemui.Gefingerpoken;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 /**
  * A helper class to handle touches on the heads-up views.
  */
 public class HeadsUpTouchHelper implements Gefingerpoken {
 
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final IStatusBarService mStatusBarService;
     private final Callback mCallback;
     private int mTrackingPointer;
@@ -45,7 +46,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
     private final HeadsUpNotificationViewController mPanel;
     private ExpandableNotificationRow mPickedChild;
 
-    public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
+    public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
             IStatusBarService statusBarService,
             Callback callback,
             HeadsUpNotificationViewController notificationPanelView) {
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 4b39854e43ff08fcc4ea3b3cd3c59ea2581b9ff5..235ed25e2ea19a85fbe88196ea07328d2c60b938 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
 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;
 
@@ -39,7 +40,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener,
     private final ShadeViewController mShadeViewController;
     private final NotificationStackScrollLayoutController mNsslController;
     private final KeyguardBypassController mKeyguardBypassController;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
 
@@ -50,7 +51,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener,
             ShadeViewController shadeViewController,
             NotificationStackScrollLayoutController nsslController,
             KeyguardBypassController keyguardBypassController,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             StatusBarStateController statusBarStateController,
             NotificationRemoteInputManager notificationRemoteInputManager) {
         mNotificationShadeWindowController = notificationShadeWindowController;
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 eedf35f1e9d437628ba95c0193274019159f128a..62b2445de13ae7678198f935f26e173ba301ad2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1573,6 +1573,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
      * notification shade's child views.
      */
     public boolean shouldInterceptTouchEvent(MotionEvent event) {
+        if (mFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+            return false;
+        }
         return mAlternateBouncerInteractor.isVisibleState();
     }
 
@@ -1581,6 +1584,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
      * showing.
      */
     public boolean onTouch(MotionEvent event) {
+        if (mFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+            return false;
+        }
+
         boolean handleTouch = shouldInterceptTouchEvent(event);
         if (handleTouch) {
             final boolean actionDown = event.getActionMasked() == MotionEvent.ACTION_DOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index dc4c7095237eb4204e09719c20571813ccbf1476..dbee080f238d1b28deeabb12977ea15f3aeaeb80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.wmshell.BubblesManager;
@@ -102,7 +103,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
     private final Executor mUiBgExecutor;
 
     private final NotificationVisibilityProvider mVisibilityProvider;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final ActivityStarter mActivityStarter;
     private final NotificationClickNotifier mClickNotifier;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -141,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
             Handler mainThreadHandler,
             Executor uiBgExecutor,
             NotificationVisibilityProvider visibilityProvider,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             ActivityStarter activityStarter,
             NotificationClickNotifier clickNotifier,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -213,7 +214,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
      */
     @Override
     public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) {
-        mLogger.logStartingActivityFromClick(entry);
+        mLogger.logStartingActivityFromClick(entry, row.isHeadsUpState(),
+                mKeyguardStateController.isVisible(),
+                mNotificationShadeWindowController.getPanelExpanded());
 
         if (mRemoteInputManager.isRemoteInputActive(entry)) {
             // We have an active remote input typed and the user clicked on the notification.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
index 2d30a12c3948d8e90ce07dcf9fc9ae98c6793dca..4211cabcbc561e4acc0c7ef5c93d5e967c89fc7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
@@ -30,11 +30,16 @@ import javax.inject.Inject
 class StatusBarNotificationActivityStarterLogger @Inject constructor(
     @NotifInteractionLog private val buffer: LogBuffer
 ) {
-    fun logStartingActivityFromClick(entry: NotificationEntry) {
+    fun logStartingActivityFromClick(entry: NotificationEntry, isHeadsUpState: Boolean,
+                                     isKeyguardVisible: Boolean, isPanelExpanded: Boolean) {
         buffer.log(TAG, DEBUG, {
             str1 = entry.logKey
+            bool1 = isHeadsUpState
+            bool2 = isKeyguardVisible
+            bool3 = isPanelExpanded
         }, {
-            "(1/5) onNotificationClicked: $str1"
+            "(1/5) onNotificationClicked: $str1 isHeadsUpState: $bool1 " +
+                    "isKeyguardVisible: $bool2 isPanelExpanded: $bool3"
         })
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index fb7f9d1ec19b2b6a754b09467dd0757ebfb36349..2d14f6b3c508ba74d8835142d3b9df6d299da77c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -31,11 +31,11 @@ import android.view.View;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.InitController;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.NotificationShadeWindowView;
 import com.android.systemui.shade.QuickSettingsController;
 import com.android.systemui.shade.ShadeViewController;
@@ -60,6 +60,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import javax.inject.Inject;
@@ -76,7 +77,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu
     private final NotificationMediaManager mMediaManager;
     private final NotificationGutsManager mGutsManager;
     private final ShadeViewController mNotificationPanel;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final AboveShelfObserver mAboveShelfObserver;
     private final DozeScrimController mDozeScrimController;
     private final NotificationsInteractor mNotificationsInteractor;
@@ -98,7 +99,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu
             Context context,
             ShadeViewController panel,
             QuickSettingsController quickSettingsController,
-            HeadsUpManagerPhone headsUp,
+            HeadsUpManager headsUp,
             NotificationShadeWindowView statusBarWindow,
             ActivityStarter activityStarter,
             NotificationStackScrollLayoutController stackScrollerController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 40bd8d3446b554ef4523e095c44af35e000d07c5..ba73c1098637cfc7fafa200a4ae605e584d0b9f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -31,15 +31,18 @@ import android.view.WindowInsets;
 
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.ScreenDecorations;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
@@ -58,13 +61,12 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
     private static final String TAG = "TouchableRegionManager";
 
     private final Context mContext;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
 
     private boolean mIsStatusBarExpanded = false;
     private boolean mShouldAdjustInsets = false;
-    private CentralSurfaces mCentralSurfaces;
     private View mNotificationShadeWindowView;
     private View mNotificationPanelView;
     private boolean mForceCollapsedUntilLayout = false;
@@ -72,6 +74,8 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
     private Region mTouchableRegion = new Region();
     private int mDisplayCutoutTouchableRegionSize;
     private int mStatusBarHeight;
+    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    private final AlternateBouncerInteractor mAlternateBouncerInteractor;
 
     private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
 
@@ -80,12 +84,14 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
             Context context,
             NotificationShadeWindowController notificationShadeWindowController,
             ConfigurationController configurationController,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             ShadeExpansionStateManager shadeExpansionStateManager,
             Provider<SceneInteractor> sceneInteractor,
             Provider<JavaAdapter> javaAdapter,
             SceneContainerFlags sceneContainerFlags,
-            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController
+            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+            PrimaryBouncerInteractor primaryBouncerInteractor,
+            AlternateBouncerInteractor alternateBouncerInteractor
     ) {
         mContext = context;
         initResources();
@@ -128,13 +134,12 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
                     this::onShadeExpansionFullyChanged);
         }
 
+        mPrimaryBouncerInteractor = primaryBouncerInteractor;
+        mAlternateBouncerInteractor = alternateBouncerInteractor;
         mOnComputeInternalInsetsListener = this::onComputeInternalInsets;
     }
 
-    protected void setup(
-            @NonNull CentralSurfaces centralSurfaces,
-            @NonNull View notificationShadeWindowView) {
-        mCentralSurfaces = centralSurfaces;
+    protected void setup(@NonNull View notificationShadeWindowView) {
         mNotificationShadeWindowView = notificationShadeWindowView;
         mNotificationPanelView = mNotificationShadeWindowView.findViewById(R.id.notification_panel);
     }
@@ -260,7 +265,8 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
         // since we don't want stray touches to go through the light reveal scrim to whatever is
         // underneath.
         return mIsStatusBarExpanded
-                || mCentralSurfaces.isBouncerShowing()
+                || mPrimaryBouncerInteractor.isShowing().getValue()
+                || mAlternateBouncerInteractor.isVisibleState()
                 || mUnlockedScreenOffAnimationController.isAnimationPlaying();
     }
 
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 babd435c62ba599e20b2e833aa57efc381f70114..63c022c5bb6b145114cfe69395220a6857e0f6aa 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
@@ -38,11 +38,11 @@ import com.android.app.animation.Interpolators;
 import com.android.app.animation.InterpolatorsAndroidX;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -74,8 +74,6 @@ import com.android.systemui.util.CarrierConfigTracker.CarrierConfigChangedListen
 import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
 import com.android.systemui.util.settings.SecureSettings;
 
-import kotlin.Unit;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -85,6 +83,7 @@ import java.util.Set;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
+import kotlin.Unit;
 
 /**
  * Contains the collapsed status bar and handles hiding/showing based on disable flags
@@ -279,7 +278,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mDumpManager.registerDumpable(getClass().getSimpleName(), this);
-        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(this);
+        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(
+                (PhoneStatusBarView) getView());
         mStatusBarFragmentComponent.init();
         mStartableStates.clear();
         for (Startable startable : mStatusBarFragmentComponent.getStartables()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
index d9a58442d856d8c51591893948294e3cb3f07d52..0618abbf00d8403f9a2f392f8f6bed09015c5fd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
@@ -27,11 +27,11 @@ import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
 import com.android.systemui.statusbar.phone.StatusBarDemoMode;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 
-import java.util.Set;
-
 import dagger.BindsInstance;
 import dagger.Subcomponent;
 
+import java.util.Set;
+
 /**
  * A subcomponent that gets re-created each time we create a new {@link CollapsedStatusBarFragment}.
  *
@@ -54,7 +54,7 @@ public interface StatusBarFragmentComponent {
     @Subcomponent.Factory
     interface Factory {
         StatusBarFragmentComponent create(
-                @BindsInstance CollapsedStatusBarFragment collapsedStatusBarFragment);
+                @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView);
     }
 
     /**
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 6ef877bd57bfce6b0c80c93836b763d1ea21383c..3741f143dd8d5f48840821156af7e9a64a5e3090 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
@@ -19,15 +19,14 @@ package com.android.systemui.statusbar.phone.fragment.dagger;
 import android.view.View;
 import android.view.ViewStub;
 
-import com.android.systemui.res.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
 import com.android.systemui.statusbar.phone.StatusBarLocation;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -49,15 +48,6 @@ public interface StatusBarFragmentModule {
     String START_SIDE_CONTENT = "start_side_content";
     String END_SIDE_CONTENT = "end_side_content";
 
-    /** */
-    @Provides
-    @RootView
-    @StatusBarFragmentScope
-    static PhoneStatusBarView providePhoneStatusBarView(
-            CollapsedStatusBarFragment collapsedStatusBarFragment) {
-        return (PhoneStatusBarView) collapsedStatusBarFragment.getView();
-    }
-
     /** */
     @Provides
     @StatusBarFragmentScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index e59ec044bece25aef0b132f1418116fa8803a6b9..cec76f3140cd5bd587a20da10e389f880742d715 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -34,8 +34,8 @@ import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.EventLogTags;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -47,7 +47,8 @@ import java.io.PrintWriter;
  * A manager which handles heads up notifications which is a special mode where
  * they simply peek from the top of the screen.
  */
-public abstract class HeadsUpManager extends AlertingNotificationManager {
+public abstract class BaseHeadsUpManager extends AlertingNotificationManager implements
+        HeadsUpManager {
     private static final String TAG = "HeadsUpManager";
     private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
 
@@ -81,7 +82,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
         }
     }
 
-    public HeadsUpManager(@NonNull final Context context,
+    public BaseHeadsUpManager(@NonNull final Context context,
             HeadsUpManagerLogger logger,
             @Main Handler handler,
             AccessibilityManagerWrapper accessibilityManagerWrapper,
@@ -131,6 +132,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
         mListeners.remove(listener);
     }
 
+    /** Updates the notification with the given key. */
     public void updateNotification(@NonNull String key, boolean alert) {
         super.updateNotification(key, alert);
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
@@ -146,7 +148,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
             // the NotificationEntry into AlertingNotificationManager's mAlertEntries map.
             return hasFullScreenIntent(entry);
         }
-        return hasFullScreenIntent(entry) && !headsUpEntry.wasUnpinned;
+        return hasFullScreenIntent(entry) && !headsUpEntry.mWasUnpinned;
     }
 
     protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) {
@@ -154,11 +156,11 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
     }
 
     protected void setEntryPinned(
-            @NonNull HeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
+            @NonNull BaseHeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
         mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned);
         NotificationEntry entry = headsUpEntry.mEntry;
         if (!isPinned) {
-            headsUpEntry.wasUnpinned = true;
+            headsUpEntry.mWasUnpinned = true;
         }
         if (entry.isRowPinned() != isPinned) {
             entry.setRowPinned(isPinned);
@@ -292,10 +294,12 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
         mUser = user;
     }
 
+    /** Returns the ID of the current user. */
     public int getUser() {
         return  mUser;
     }
 
+    @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("HeadsUpManager state:");
         dumpInternal(pw, args);
@@ -309,9 +313,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
         for (AlertEntry entry: mAlertEntries.values()) {
             pw.print("  HeadsUpEntry="); pw.println(entry.mEntry);
         }
-        int N = mSnoozedPackages.size();
-        pw.println("  snoozed packages: " + N);
-        for (int i = 0; i < N; i++) {
+        int n = mSnoozedPackages.size();
+        pw.println("  snoozed packages: " + n);
+        for (int i = 0; i < n; i++) {
             pw.print("    "); pw.print(mSnoozedPackages.valueAt(i));
             pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));
         }
@@ -399,20 +403,20 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
      *
      * @param entry the entry that might be indirectly removed by the user's action
      *
-     * @see com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator#mActionPressListener
+     * @see HeadsUpCoordinator#mActionPressListener
      * @see #canRemoveImmediately(String)
      */
     public void setUserActionMayIndirectlyRemove(@NonNull NotificationEntry entry) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
         if (headsUpEntry != null) {
-            headsUpEntry.userActionMayIndirectlyRemove = true;
+            headsUpEntry.mUserActionMayIndirectlyRemove = true;
         }
     }
 
     @Override
     public boolean canRemoveImmediately(@NonNull String key) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
-        if (headsUpEntry != null && headsUpEntry.userActionMayIndirectlyRemove) {
+        if (headsUpEntry != null && headsUpEntry.mUserActionMayIndirectlyRemove) {
             return true;
         }
         return super.canRemoveImmediately(key);
@@ -424,9 +428,6 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
         return new HeadsUpEntry();
     }
 
-    public void onDensityOrFontScaleChanged() {
-    }
-
     /**
      * Determines if the notification is for a critical call that must display on top of an active
      * input notification.
@@ -445,16 +446,16 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
      * lifecycle automatically when created.
      */
     protected class HeadsUpEntry extends AlertEntry {
-        public boolean remoteInputActive;
-        public boolean userActionMayIndirectlyRemove;
+        public boolean mRemoteInputActive;
+        public boolean mUserActionMayIndirectlyRemove;
 
-        protected boolean expanded;
-        protected boolean wasUnpinned;
+        protected boolean mExpanded;
+        protected boolean mWasUnpinned;
 
         @Override
         public boolean isSticky() {
-            return (mEntry.isRowPinned() && expanded)
-                    || remoteInputActive
+            return (mEntry.isRowPinned() && mExpanded)
+                    || mRemoteInputActive
                     || hasFullScreenIntent(mEntry);
         }
 
@@ -490,9 +491,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
                 return 1;
             }
 
-            if (remoteInputActive && !headsUpEntry.remoteInputActive) {
+            if (mRemoteInputActive && !headsUpEntry.mRemoteInputActive) {
                 return -1;
-            } else if (!remoteInputActive && headsUpEntry.remoteInputActive) {
+            } else if (!mRemoteInputActive && headsUpEntry.mRemoteInputActive) {
                 return 1;
             }
 
@@ -500,14 +501,14 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
         }
 
         public void setExpanded(boolean expanded) {
-            this.expanded = expanded;
+            this.mExpanded = expanded;
         }
 
         @Override
         public void reset() {
             super.reset();
-            expanded = false;
-            remoteInputActive = false;
+            mExpanded = false;
+            mRemoteInputActive = false;
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d9527fe98b1a34a54ab2a81d431f5f502945d99c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
@@ -0,0 +1,245 @@
+package com.android.systemui.statusbar.policy
+
+import android.graphics.Region
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import dagger.Binds
+import dagger.Module
+import java.io.PrintWriter
+import java.util.stream.Stream
+import javax.inject.Inject
+
+/**
+ * A manager which handles heads up notifications which is a special mode where they simply peek
+ * from the top of the screen.
+ */
+interface HeadsUpManager : Dumpable {
+    /** The stream of all current notifications managed by this manager. */
+    val allEntries: Stream<NotificationEntry>
+
+    /** Add a listener to receive callbacks onHeadsUpGoingAway. */
+    fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange)
+
+    /** Adds an OnHeadUpChangedListener to observe events. */
+    fun addListener(listener: OnHeadsUpChangedListener)
+
+    fun addSwipedOutNotification(key: String)
+
+    /**
+     * Whether or not the alert can be removed currently. If it hasn't been on screen long enough it
+     * should not be removed unless forced
+     *
+     * @param key the key to check if removable
+     * @return true if the alert entry can be removed
+     */
+    fun canRemoveImmediately(key: String): Boolean
+
+    /**
+     * Compare two entries and decide how they should be ranked.
+     *
+     * @return -1 if the first argument should be ranked higher than the second, 1 if the second one
+     *   should be ranked higher and 0 if they are equal.
+     */
+    fun compare(a: NotificationEntry?, b: NotificationEntry?): Int
+    /**
+     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
+     * longer.
+     */
+    fun extendHeadsUp()
+
+    /** Returns when a HUN entry should be removed in milliseconds from now. */
+    fun getEarliestRemovalTime(key: String?): Long
+
+    /** Returns the top Heads Up Notification, which appears to show at first. */
+    fun getTopEntry(): NotificationEntry?
+
+    /**
+     * Gets the touchable region needed for heads up notifications. Returns null if no touchable
+     * region is required (ie: no heads up notification currently exists).
+     */
+    fun getTouchableRegion(): Region?
+
+    /**
+     * Whether or not there are any active alerting notifications.
+     *
+     * @return true if there is an alert, false otherwise
+     */
+    fun hasNotifications(): Boolean = false
+
+    /** Returns whether there are any pinned Heads Up Notifications or not. */
+    fun hasPinnedHeadsUp(): Boolean
+
+    /** Returns whether or not the given notification is alerting and managed by this manager. */
+    fun isAlerting(key: String): Boolean
+
+    fun isHeadsUpGoingAway(): Boolean
+
+    /** Returns if the given notification is snoozed or not. */
+    fun isSnoozed(packageName: String): Boolean
+
+    /** Returns whether the entry is (pinned and expanded) or (has an active remote input). */
+    fun isSticky(key: String?): Boolean
+
+    fun isTrackingHeadsUp(): Boolean
+
+    fun onExpandingFinished()
+
+    /** Removes the OnHeadUpChangedListener from the observer list. */
+    fun removeListener(listener: OnHeadsUpChangedListener)
+
+    /**
+     * Try to remove the notification. May not succeed if the notification has not been shown long
+     * enough and needs to be kept around.
+     *
+     * @param key the key of the notification to remove
+     * @param releaseImmediately force a remove regardless of earliest removal time
+     * @return true if notification is removed, false otherwise
+     */
+    fun removeNotification(key: String, releaseImmediately: Boolean): Boolean
+
+    /**
+     * Try to remove the notification. May not succeed if the notification has not been shown long
+     * enough and needs to be kept around.
+     *
+     * @param key the key of the notification to remove
+     * @param releaseImmediately force a remove regardless of earliest removal time
+     * @param animate if true, animate the removal
+     * @return true if notification is removed, false otherwise
+     */
+    fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean): Boolean
+
+    /** Clears all managed notifications. */
+    fun releaseAllImmediately()
+
+    fun setAnimationStateHandler(handler: AnimationStateHandler)
+
+    /**
+     * Set an entry to be expanded and therefore stick in the heads up area if it's pinned until
+     * it's collapsed again.
+     */
+    fun setExpanded(entry: NotificationEntry, expanded: Boolean)
+
+    /**
+     * Sets whether an entry's guts are exposed and therefore it should stick in the heads up area
+     * if it's pinned until it's hidden again.
+     */
+    fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean)
+
+    /**
+     * Set that we are exiting the headsUp pinned mode, but some notifications might still be
+     * animating out. This is used to keep the touchable regions in a reasonable state.
+     */
+    fun setHeadsUpGoingAway(headsUpGoingAway: Boolean)
+
+    /**
+     * Notifies that a remote input textbox in notification gets active or inactive.
+     *
+     * @param entry The entry of the target notification.
+     * @param remoteInputActive True to notify active, False to notify inactive.
+     */
+    fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean)
+
+    fun setTrackingHeadsUp(tracking: Boolean)
+
+    /** Sets the current user. */
+    fun setUser(user: Int)
+
+    /**
+     * Notes that the user took an action on an entry that might indirectly cause the system or the
+     * app to remove the notification.
+     *
+     * @param entry the entry that might be indirectly removed by the user's action
+     * @see
+     *   com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator.mActionPressListener
+     * @see .canRemoveImmediately
+     */
+    fun setUserActionMayIndirectlyRemove(entry: NotificationEntry)
+
+    /**
+     * Decides whether a click is invalid for a notification, i.e. it has not been shown long enough
+     * that a user might have consciously clicked on it.
+     *
+     * @param key the key of the touched notification
+     * @return whether the touch is invalid and should be discarded
+     */
+    fun shouldSwallowClick(key: String): Boolean
+
+    /**
+     * Called when posting a new notification that should alert the user and appear on screen. Adds
+     * the notification to be managed.
+     *
+     * @param entry entry to show
+     */
+    fun showNotification(entry: NotificationEntry)
+
+    fun snooze()
+
+    /**
+     * Unpins all pinned Heads Up Notifications.
+     *
+     * @param userUnPinned The unpinned action is trigger by user real operation.
+     */
+    fun unpinAll(userUnPinned: Boolean)
+
+    fun updateNotification(key: String, alert: Boolean)
+}
+
+/** Sets the animation state of the HeadsUpManager. */
+interface AnimationStateHandler {
+    fun setHeadsUpGoingAwayAnimationsAllowed(allowed: Boolean)
+}
+
+/** Listener to register for HeadsUpNotification Phone changes. */
+interface OnHeadsUpPhoneListenerChange {
+    /**
+     * Called when a heads up notification is 'going away' or no longer 'going away'. See
+     * [HeadsUpManager.setHeadsUpGoingAway].
+     */
+    fun onHeadsUpGoingAwayStateChanged(headsUpGoingAway: Boolean)
+}
+
+/* No op impl of HeadsUpManager. */
+class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager {
+    override val allEntries = Stream.empty<NotificationEntry>()
+    override fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange) {}
+    override fun addListener(listener: OnHeadsUpChangedListener) {}
+    override fun addSwipedOutNotification(key: String) {}
+    override fun canRemoveImmediately(key: String) = false
+    override fun compare(a: NotificationEntry?, b: NotificationEntry?) = 0
+    override fun dump(pw: PrintWriter, args: Array<out String>) {}
+    override fun extendHeadsUp() {}
+    override fun getEarliestRemovalTime(key: String?) = 0L
+    override fun getTouchableRegion(): Region? = null
+    override fun getTopEntry() = null
+    override fun hasPinnedHeadsUp() = false
+    override fun isAlerting(key: String) = false
+    override fun isHeadsUpGoingAway() = false
+    override fun isSnoozed(packageName: String) = false
+    override fun isSticky(key: String?) = false
+    override fun isTrackingHeadsUp() = false
+    override fun onExpandingFinished() {}
+    override fun releaseAllImmediately() {}
+    override fun removeListener(listener: OnHeadsUpChangedListener) {}
+    override fun removeNotification(key: String, releaseImmediately: Boolean) = false
+    override fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean) =
+        false
+    override fun setAnimationStateHandler(handler: AnimationStateHandler) {}
+    override fun setExpanded(entry: NotificationEntry, expanded: Boolean) {}
+    override fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean) {}
+    override fun setHeadsUpGoingAway(headsUpGoingAway: Boolean) {}
+    override fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean) {}
+    override fun setTrackingHeadsUp(tracking: Boolean) {}
+    override fun setUser(user: Int) {}
+    override fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) {}
+    override fun shouldSwallowClick(key: String): Boolean = false
+    override fun showNotification(entry: NotificationEntry) {}
+    override fun snooze() {}
+    override fun unpinAll(userUnPinned: Boolean) {}
+    override fun updateNotification(key: String, alert: Boolean) {}
+}
+
+@Module
+interface HeadsUpEmptyImplModule {
+    @Binds @SysUISingleton fun bindsHeadsUpManager(noOpHum: HeadsUpManagerEmptyImpl): HeadsUpManager
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt
index c302d6aeadbccea4e4a73135fb5017759e6d7d7a..859e636a7714d72f671ae7eb18579c3fde22901f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy
 
 import android.content.res.Resources
 import com.android.systemui.res.R
+import javax.inject.Inject
 
 /**
  * Fake SplitShadeStateController
@@ -24,7 +25,7 @@ import com.android.systemui.res.R
  * Identical behaviour to legacy implementation (that used LargeScreenUtils.kt) I.E., behaviour
  * based solely on resources, no extra flag logic.
  */
-class ResourcesSplitShadeStateController : SplitShadeStateController {
+class ResourcesSplitShadeStateController @Inject constructor() : SplitShadeStateController {
     override fun shouldUseSplitNotificationShade(resources: Resources): Boolean {
         return resources.getBoolean(R.bool.config_use_split_notification_shade)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index a77c69236946f8f75252a6c04a640d7ff224d7f9..818ba9512e15391253940df02ef8887cba3a3485 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepository;
 import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepositoryImpl;
+import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepositoryModule;
 
 import dagger.Binds;
 import dagger.Module;
@@ -80,7 +81,7 @@ import java.util.concurrent.Executor;
 import javax.inject.Named;
 
 /** Dagger Module for code in the statusbar.policy package. */
-@Module
+@Module(includes = { DeviceProvisioningRepositoryModule.class })
 public interface StatusBarPolicyModule {
 
     String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1160d657ba88a2bd19a4b52416ced2be4c0ffe24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.statusbar.policy.data.repository
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Tracks state related to device provisioning. */
+interface DeviceProvisioningRepository {
+    /**
+     * Whether this device has been provisioned.
+     *
+     * @see android.provider.Settings.Global.DEVICE_PROVISIONED
+     */
+    val isDeviceProvisioned: Flow<Boolean>
+
+    /** Whether Factory Reset Protection (FRP) is currently active, locking the device. */
+    val isFactoryResetProtectionActive: Flow<Boolean>
+}
+
+@Module
+interface DeviceProvisioningRepositoryModule {
+    @Binds fun bindsImpl(impl: DeviceProvisioningRepositoryImpl): DeviceProvisioningRepository
+}
+
+class DeviceProvisioningRepositoryImpl
+@Inject
+constructor(
+    private val deviceProvisionedController: DeviceProvisionedController,
+) : DeviceProvisioningRepository {
+
+    override val isDeviceProvisioned: Flow<Boolean> = conflatedCallbackFlow {
+        val listener =
+            object : DeviceProvisionedController.DeviceProvisionedListener {
+                override fun onDeviceProvisionedChanged() {
+                    trySend(deviceProvisionedController.isDeviceProvisioned)
+                }
+            }
+        deviceProvisionedController.addCallback(listener)
+        trySend(deviceProvisionedController.isDeviceProvisioned)
+        awaitClose { deviceProvisionedController.removeCallback(listener) }
+    }
+
+    override val isFactoryResetProtectionActive: Flow<Boolean> = conflatedCallbackFlow {
+        val listener =
+            object : DeviceProvisionedController.DeviceProvisionedListener {
+                override fun onFrpActiveChanged() {
+                    trySend(deviceProvisionedController.isFrpActive)
+                }
+            }
+        deviceProvisionedController.addCallback(listener)
+        trySend(deviceProvisionedController.isFrpActive)
+        awaitClose { deviceProvisionedController.removeCallback(listener) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index ce9d6fd752c5bb29dd005a6cca216b5f6342d6d8..dbc3bf3a75a2c4d38f4066b9c5648e9a1041f144 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -325,6 +325,7 @@ constructor(
                             addAction(Intent.ACTION_USER_SWITCHED)
                             addAction(Intent.ACTION_USER_STOPPED)
                             addAction(Intent.ACTION_USER_UNLOCKED)
+                            addAction(Intent.ACTION_LOCALE_CHANGED)
                         },
                     user = UserHandle.SYSTEM,
                     map = { intent, _ -> intent },
@@ -615,6 +616,7 @@ constructor(
     ) {
         val shouldRefreshAllUsers =
             when (intent.action) {
+                Intent.ACTION_LOCALE_CHANGED -> true
                 Intent.ACTION_USER_SWITCHED -> {
                     dismissDialog()
                     val selectedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
@@ -644,6 +646,11 @@ constructor(
     }
 
     private fun restartSecondaryService(@UserIdInt userId: Int) {
+        // Do not start service for user that is marked for deletion.
+        if (!manager.aliveUsers.map { it.id }.contains(userId)) {
+            return
+        }
+
         val intent = Intent(applicationContext, SystemUISecondaryUserService::class.java)
         // Disconnect from the old secondary user's service
         val secondaryUserId = repository.secondaryUserId
@@ -657,6 +664,7 @@ constructor(
 
         // Connect to the new secondary user's service (purely to ensure that a persistent
         // SystemUI application is created for that user)
+
         if (userId != Process.myUserHandle().identifier) {
             applicationContext.startServiceAsUser(
                 intent,
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index d3f83b1e18bd5131bdadd0f23f965317f029377b..20f0fa8cf46bb83b4cdf443d044bdc2e2e9e7ecc 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -68,6 +68,7 @@ constructor(
 
     private val hasCancelButtonBeenClicked = MutableStateFlow(false)
     private val isFinishRequiredDueToExecutedAction = MutableStateFlow(false)
+    private val userSwitched = MutableStateFlow(false)
 
     /**
      * Whether the observer should finish the experience. Once consumed, [onFinished] must be called
@@ -89,6 +90,7 @@ constructor(
     fun onFinished() {
         hasCancelButtonBeenClicked.value = false
         isFinishRequiredDueToExecutedAction.value = false
+        userSwitched.value = false
     }
 
     /** Notifies that the user has clicked the "open menu" button. */
@@ -121,8 +123,9 @@ constructor(
             hasCancelButtonBeenClicked,
             // If an executed action told us to finish, we should finish,
             isFinishRequiredDueToExecutedAction,
-        ) { cancelButtonClicked, executedActionFinish ->
-            cancelButtonClicked || executedActionFinish
+            userSwitched,
+        ) { cancelButtonClicked, executedActionFinish, userSwitched ->
+            cancelButtonClicked || executedActionFinish || userSwitched
         }
 
     private fun toViewModel(
@@ -191,7 +194,10 @@ constructor(
         return if (!model.isSelectable) {
             null
         } else {
-            { userInteractor.selectUser(model.id) }
+            {
+                userInteractor.selectUser(model.id)
+                userSwitched.value = true
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ac04d31041b6b09b82ed961d0b6af3f30fa48c35
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt
@@ -0,0 +1,50 @@
+package com.android.systemui.util
+
+import java.lang.ref.SoftReference
+import java.lang.ref.WeakReference
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+/**
+ * Creates a Kotlin idiomatic weak reference.
+ *
+ * Usage:
+ * ```
+ * var weakReferenceObj: Object? by weakReference(null)
+ * weakReferenceObj = Object()
+ * ```
+ */
+fun <T> weakReference(obj: T? = null): ReadWriteProperty<Any?, T?> {
+    return object : ReadWriteProperty<Any?, T?> {
+        var weakRef = WeakReference<T?>(obj)
+        override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
+            return weakRef.get()
+        }
+
+        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
+            weakRef = WeakReference(value)
+        }
+    }
+}
+
+/**
+ * Creates a Kotlin idiomatic soft reference.
+ *
+ * Usage:
+ * ```
+ * var softReferenceObj: Object? by softReference(null)
+ * softReferenceObj = Object()
+ * ```
+ */
+fun <T> softReference(obj: T? = null): ReadWriteProperty<Any?, T?> {
+    return object : ReadWriteProperty<Any?, T?> {
+        var softRef = SoftReference<T?>(obj)
+        override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
+            return softRef.get()
+        }
+
+        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
+            softRef = SoftReference(value)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 750b6f95d52e0b6f9df9592ff6e812600eeda551..2132904caa847c4635cb51d02f601223afe146a4 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -40,12 +40,13 @@ import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -68,6 +69,7 @@ public class WalletActivity extends ComponentActivity implements
     private final Executor mExecutor;
     private final Handler mHandler;
     private final FalsingManager mFalsingManager;
+    private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
     private FalsingCollector mFalsingCollector;
     private final UserTracker mUserTracker;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -91,7 +93,8 @@ public class WalletActivity extends ComponentActivity implements
             UserTracker userTracker,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarKeyguardViewManager keyguardViewManager,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger,
+            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) {
         mKeyguardStateController = keyguardStateController;
         mKeyguardDismissUtil = keyguardDismissUtil;
         mActivityStarter = activityStarter;
@@ -103,6 +106,7 @@ public class WalletActivity extends ComponentActivity implements
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mKeyguardViewManager = keyguardViewManager;
         mUiEventLogger = uiEventLogger;
+        mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
     }
 
     @Override
@@ -209,6 +213,7 @@ public class WalletActivity extends ComponentActivity implements
                 true,
                 Utils.getColorAttrDefaultColor(
                         this, com.android.internal.R.attr.colorAccentPrimary));
+        mKeyguardFaceAuthInteractor.onWalletLaunched();
         mKeyguardViewManager.requestFace(true);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index 8990583cf9de73575a67343aa126077d9710596d..c1be44ab8a8568c2e3a3ead1988e15d9aded2982 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -18,61 +18,94 @@ package com.android
 import android.app.ActivityManager
 import android.app.admin.DevicePolicyManager
 import android.os.UserManager
+import android.util.DisplayMetrics
+import com.android.internal.logging.MetricsLogger
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.ScreenLifecycle
+import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.dagger.BroadcastDispatcherLog
 import com.android.systemui.log.dagger.SceneFrameworkLog
+import com.android.systemui.media.controls.ui.MediaHierarchyManager
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.NotificationShadeDepthController
+import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.stack.AmbientState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.util.mockito.mock
 import com.android.wm.shell.bubbles.Bubbles
+import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import java.util.Optional
 
-@Module
+@Module(includes = [TestMocksModule.Bindings::class])
 data class TestMocksModule(
     @get:Provides val activityStarter: ActivityStarter = mock(),
+    @get:Provides val ambientState: AmbientState = mock(),
     @get:Provides val bubbles: Optional<Bubbles> = Optional.of(mock()),
-    @get:Provides val configurationController: ConfigurationController = mock(),
     @get:Provides val darkIconDispatcher: DarkIconDispatcher = mock(),
     @get:Provides val demoModeController: DemoModeController = mock(),
     @get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
     @get:Provides val dozeParameters: DozeParameters = mock(),
+    @get:Provides val dumpManager: DumpManager = mock(),
     @get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
     @get:Provides val keyguardBypassController: KeyguardBypassController = mock(),
     @get:Provides val keyguardSecurityModel: KeyguardSecurityModel = mock(),
     @get:Provides val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(),
-    @get:Provides val notifListener: NotificationListener = mock(),
-    @get:Provides val notifMediaManager: NotificationMediaManager = mock(),
+    @get:Provides val mediaHierarchyManager: MediaHierarchyManager = mock(),
+    @get:Provides val notificationListener: NotificationListener = mock(),
+    @get:Provides val notificationLockscreenUserManager: NotificationLockscreenUserManager = mock(),
+    @get:Provides val notificationMediaManager: NotificationMediaManager = mock(),
+    @get:Provides val notificationShadeDepthController: NotificationShadeDepthController = mock(),
+    @get:Provides
+    val notificationStackScrollLayoutController: NotificationStackScrollLayoutController = mock(),
+    @get:Provides val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock(),
+    @get:Provides val notificationWakeUpCoordinator: NotificationWakeUpCoordinator = mock(),
+    @get:Provides val screenLifecycle: ScreenLifecycle = mock(),
     @get:Provides val screenOffAnimController: ScreenOffAnimationController = mock(),
-    @get:Provides val splitShadeStateController: SplitShadeStateController = mock(),
-    @get:Provides val statusBarStateController: StatusBarStateController = mock(),
+    @get:Provides val scrimController: ScrimController = mock(),
+    @get:Provides val statusBarStateController: SysuiStatusBarStateController = mock(),
     @get:Provides val statusBarWindowController: StatusBarWindowController = mock(),
-    @get:Provides val wakeUpCoordinator: NotificationWakeUpCoordinator = mock(),
+    @get:Provides val wakefulnessLifecycle: WakefulnessLifecycle = mock(),
 
     // log buffers
     @get:[Provides BroadcastDispatcherLog]
     val broadcastDispatcherLogger: LogBuffer = mock(),
     @get:[Provides SceneFrameworkLog]
     val sceneLogger: LogBuffer = mock(),
+    @get:Provides val lsShadeTransitionLogger: LSShadeTransitionLogger = mock(),
 
     // framework mocks
     @get:Provides val activityManager: ActivityManager = mock(),
     @get:Provides val devicePolicyManager: DevicePolicyManager = mock(),
+    @get:Provides val displayMetrics: DisplayMetrics = mock(),
+    @get:Provides val metricsLogger: MetricsLogger = mock(),
     @get:Provides val userManager: UserManager = mock(),
-)
+) {
+    @Module
+    interface Bindings {
+        @Binds
+        fun bindStatusBarStateController(
+            sysuiStatusBarStateController: SysuiStatusBarStateController,
+        ): StatusBarStateController
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index f943acd9180ea903e53e6112bdf5e16f2e166b0e..d8a2c5f76fcea1eeb38fc2b2f2a6a9c41c91c617 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -47,7 +46,6 @@ import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPasswordViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index e09009389f8bee8ae23e80b92dce104589f7b772..dc1618d128b3201a51e3ed573baf675f1be55b3e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
@@ -53,7 +52,6 @@ import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPatternViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 8322b37151ded35a497dcb1b7f1880ccb98f975b..4a24e4a1f40f6ae077da7d920c070577522ce7d1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -31,14 +31,13 @@ import androidx.test.filters.SmallTest;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.SingleTapClassifier;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.res.R;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -47,7 +46,6 @@ import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 2f08804d8c051ee00e0de4f94f2e465f172b46dd..9df4dd4df4d2908175c56ffafcf5ae99f1436e55 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -26,7 +26,6 @@ import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
@@ -53,7 +52,6 @@ import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPinViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index d54843d39d212abea7c22261fd9e094e7263cbbb..62f9a9dcce70a9c22f4fb2688d2394b6142eb756 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -36,7 +36,6 @@ import com.android.internal.logging.UiEventLogger
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate
 import com.android.systemui.biometrics.SideFpsController
@@ -100,7 +99,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
@@ -812,6 +810,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                     SceneKey.Bouncer,
                     flowOf(.5f),
                     false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -827,7 +826,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                     SceneKey.Bouncer,
                     SceneKey.Gone,
                     flowOf(.5f),
-                    false
+                    false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -844,7 +844,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                     SceneKey.Gone,
                     SceneKey.Bouncer,
                     flowOf(.5f),
-                    false
+                    false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -862,7 +863,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                     SceneKey.Bouncer,
                     SceneKey.Gone,
                     flowOf(.5f),
-                    false
+                    false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -878,6 +880,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                     SceneKey.Lockscreen,
                     flowOf(.5f),
                     false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason")
@@ -895,6 +898,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                     SceneKey.Gone,
                     flowOf(.5f),
                     false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index aad11d90f5a43d320d722b1b1ff300e4207131cc..156e06843d15df1952728095c6324d700a1951e3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -56,11 +56,10 @@ import androidx.constraintlayout.widget.ConstraintSet;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingA11yDelegate;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.user.data.source.UserRecord;
 import com.android.systemui.util.settings.GlobalSettings;
@@ -76,7 +75,6 @@ import org.mockito.junit.MockitoRule;
 import java.util.ArrayList;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityContainerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
index b02b1f9df9fbcba821f47d630b4c7b5f2ff5335b..7bb6ef1c889589b3189dab3b66116db20e3ba4f6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -35,10 +35,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.res.R;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,7 +49,6 @@ import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index d0bb5a9993271a5e9354dd5900e4eb15a76c9848..4290b8b28687cb442ba119093eac9a4a05e9a88e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -44,7 +43,6 @@ import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardSimPinViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index 59cd26cc6b9be0653fc8e61d7d0a0f6933e7c42f..31ee6411f93b55965de7e5b555e23fc2b1b7924a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -40,7 +39,6 @@ import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardSimPukViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index e4e2b0a8d89f1b79efc291dbfef3d96f48cd1ed0..9a908d778943fb1b57ad31060996696c79ee82e3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -29,9 +29,9 @@ import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
 
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.ClockConfig;
 import com.android.systemui.plugins.ClockController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
@@ -81,7 +81,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll
     public void updatePosition_primaryClockAnimation() {
         ClockController mockClock = mock(ClockController.class);
         when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
-        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", false, true));
+        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", false, true));
 
         mController.updatePosition(10, 15, 20f, true);
 
@@ -96,7 +96,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll
     public void updatePosition_alternateClockAnimation() {
         ClockController mockClock = mock(ClockController.class);
         when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
-        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", true, true));
+        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", true, true));
 
         mController.updatePosition(10, 15, 20f, true);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 59c7e7669b63ccb8d93f7f2c452315a83108ecdb..8faf715521f8232594f11f7aa9a055a8f417543f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -166,6 +166,9 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
         waitForIdleSync()
         verify(controller).onLaunchAnimationCancelled()
         verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+        verify(listener).onLaunchAnimationCancelled()
+        verify(listener, never()).onLaunchAnimationStart()
+        assertNull(runner.delegate)
     }
 
     @Test
@@ -176,6 +179,9 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
         waitForIdleSync()
         verify(controller).onLaunchAnimationCancelled()
         verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+        verify(listener).onLaunchAnimationCancelled()
+        verify(listener, never()).onLaunchAnimationStart()
+        assertNull(runner.delegate)
     }
 
     @Test
@@ -194,6 +200,15 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
         }
     }
 
+    @Test
+    fun disposeRunner_delegateDereferenced() {
+        val runner = activityLaunchAnimator.createRunner(controller)
+        assertNotNull(runner.delegate)
+        runner.dispose()
+        waitForIdleSync()
+        assertNull(runner.delegate)
+    }
+
     private fun fakeWindow(): RemoteAnimationTarget {
         val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
         val taskInfo = ActivityManager.RunningTaskInfo()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 2bc0171939b4e88fd98360b36b7d0b35e1d7a495..885abcb72f1a4b4a140c424aea2a0ffee9a212d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -17,12 +17,15 @@
 package com.android.systemui.biometrics;
 
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+
 import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotSame;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -79,7 +82,6 @@ import androidx.test.filters.SmallTest;
 import com.android.internal.R;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
 import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
@@ -114,7 +116,6 @@ import java.util.Random;
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @SmallTest
-@RoboPilotTest
 public class AuthControllerTest extends SysuiTestCase {
 
     private static final long REQUEST_ID = 22;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 73654609ad7f3fdbf35215474fa3dce77d4f14dd..d68a3131da4c286e36be1017bb2bbe40b9728d10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -16,36 +16,18 @@
 
 package com.android.systemui.biometrics
 
-import android.app.ActivityManager
-import android.os.UserManager
 import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
-import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.GuestUserInteractor
-import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
-import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
-import com.android.systemui.user.domain.interactor.UserInteractor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.domain.UserDomainLayerModule
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -58,91 +40,27 @@ import org.mockito.MockitoAnnotations
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
-    private val testDispatcher = utils.testDispatcher
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val featureFlags = FakeFeatureFlags()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val shadeRepository = FakeShadeRepository()
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val userRepository = FakeUserRepository()
-    private val configurationRepository = FakeConfigurationRepository()
-    private val sharedNotificationContainerInteractor =
-        SharedNotificationContainerInteractor(
-            configurationRepository,
-            mContext,
-            ResourcesSplitShadeStateController()
-        )
-
-    private lateinit var detector: AuthDialogPanelInteractionDetector
-    private lateinit var shadeInteractor: ShadeInteractor
-    private lateinit var userInteractor: UserInteractor
+
+    private val testComponent: TestComponent =
+        DaggerAuthDialogPanelInteractionDetectorTest_TestComponent.factory()
+            .create(
+                test = this,
+                featureFlags =
+                    FakeFeatureFlagsClassicModule {
+                        set(Flags.FACE_AUTH_REFACTOR, false)
+                        set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                    },
+            )
 
     @Mock private lateinit var action: Runnable
-    @Mock private lateinit var activityManager: ActivityManager
-    @Mock private lateinit var activityStarter: ActivityStarter
-    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock private lateinit var guestInteractor: GuestUserInteractor
-    @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
-    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
-    @Mock private lateinit var manager: UserManager
-    @Mock private lateinit var uiEventLogger: UiEventLogger
+
+    private val testScope = testComponent.testScope
+    private val shadeRepository = testComponent.shadeRepository
+    private val detector = testComponent.detector
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-
-        featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
-        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
-
-        val refreshUsersScheduler =
-            RefreshUsersScheduler(
-                applicationScope = testScope.backgroundScope,
-                mainDispatcher = testDispatcher,
-                repository = userRepository,
-            )
-        userInteractor =
-            UserInteractor(
-                applicationContext = context,
-                repository = userRepository,
-                activityStarter = activityStarter,
-                keyguardInteractor =
-                    KeyguardInteractorFactory.create(featureFlags = featureFlags)
-                        .keyguardInteractor,
-                featureFlags = featureFlags,
-                manager = manager,
-                headlessSystemUserMode = headlessSystemUserMode,
-                applicationScope = testScope.backgroundScope,
-                telephonyInteractor =
-                    TelephonyInteractor(
-                        repository = FakeTelephonyRepository(),
-                    ),
-                broadcastDispatcher = fakeBroadcastDispatcher,
-                keyguardUpdateMonitor = keyguardUpdateMonitor,
-                backgroundDispatcher = testDispatcher,
-                activityManager = activityManager,
-                refreshUsersScheduler = refreshUsersScheduler,
-                guestUserInteractor = guestInteractor,
-                uiEventLogger = uiEventLogger,
-                userRestrictionChecker = mock(),
-            )
-        shadeInteractor =
-            ShadeInteractor(
-                testScope.backgroundScope,
-                disableFlagsRepository,
-                sceneContainerFlags,
-                { sceneInteractor },
-                keyguardRepository,
-                userSetupRepository,
-                deviceProvisionedController,
-                userInteractor,
-                sharedNotificationContainerInteractor,
-                shadeRepository,
-            )
-        detector = AuthDialogPanelInteractionDetector(testScope, { shadeInteractor })
     }
 
     @Test
@@ -215,4 +133,27 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
             // Clean up job
             detector.disable()
         }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val detector: AuthDialogPanelInteractionDetector
+        val shadeRepository: FakeShadeRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
index 8547fa33c9de487272031bc829de854c4f4670bb..714461b715d6f97c225c962208893cae91a72e3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
@@ -38,7 +38,6 @@ import android.view.Surface;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import kotlin.Unit;
@@ -53,7 +52,6 @@ import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class BiometricDisplayListenerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
index ab5d8bea585b5a0b630567c602285796ca40c138..39f0d570cb261458a84cb1289418cadfb0bcb841 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.biometrics
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.logging.BiometricMessageDeferralLogger
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import org.junit.Assert.assertEquals
@@ -34,7 +33,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class FaceHelpMessageDeferralTest : SysuiTestCase() {
     val threshold = .75f
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index 57cf834bfa38b14071cfd8682cc0aa4572eb4a61..ef06e0efa01d10a3ae9d472f358c8fb76a35ec88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -53,7 +53,6 @@ import androidx.test.filters.SmallTest
 import com.airbnb.lottie.LottieAnimationView
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.SysuiTestableContext
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
@@ -98,7 +97,6 @@ private const val SENSOR_ID = 1
 private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class SideFpsControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
index 469f65a6cae553d83e149229572856c58de02596..e2aa984de46b37ab0be512d7b8a667af6b6cbf9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
@@ -19,7 +19,6 @@ 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.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dump.DumpManager
@@ -35,7 +34,6 @@ import org.mockito.Mock
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsBpViewControllerTest : SysuiTestCase() {
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 21e614f3db3a59af3f381955976c3d3b07e69f77..e9e9624580b3a7db5564c0191790298442b3aca9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -38,7 +38,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
@@ -83,7 +82,6 @@ private const val SENSOR_HEIGHT = 60
 
 @ExperimentalCoroutinesApi
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 class UdfpsControllerOverlayTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index ee3bd0d79ad87bd6e2ce4ed736a10e6be19b0695..a36f4e9ac2176792930687a5d01472f2a4fce7f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -20,12 +20,15 @@ import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPR
 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 com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
+
 import static junit.framework.Assert.assertEquals;
 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;
@@ -74,8 +77,6 @@ import androidx.test.filters.SmallTest;
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
@@ -94,6 +95,7 @@ import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -125,7 +127,6 @@ import java.util.Optional;
 import javax.inject.Provider;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class UdfpsControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
index 280bfdf1aa8ccae879582fd6f2267126346f5844..cd9189bef7f189c5901fde10946946dd1c61e4b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
@@ -27,7 +27,6 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Test;
@@ -38,7 +37,6 @@ import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-@RoboPilotTest
 public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
     @Test
     public void testUdfpsBottomSpacerHeightForPortrait() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
index 1afb223b408953db417006b0c023c37a9dd7b9e7..5239966f192302c3f2e442cce9854782daa0b2cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
@@ -30,7 +30,6 @@ import android.testing.TestableLooper.RunWithLooper;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.concurrency.FakeExecution;
 
@@ -41,7 +40,6 @@ import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class UdfpsDisplayModeTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
index 8508f45b02f3288739c498808de6ae4cb8d7338c..b018a3e2ca6cf1e6d4fb69ea49b896bd424b9c10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
@@ -31,14 +31,12 @@ import android.view.MotionEvent;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.statusbar.StatusBarState;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index 17f435b75d5a1e1fe0797c1051988aa76ec3a49d..da4548bc14c0158ce6812d378126b54581b06223 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -21,7 +21,6 @@ import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
@@ -58,7 +57,6 @@ import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
-@RoboPilotTest
 @TestableLooper.RunWithLooper
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
index 6d552544fee7748b58fb3bb0c66b35aa7020faab..8b374ae541271536473177d2530dc698cb08216b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
@@ -21,7 +21,6 @@ import android.testing.TestableLooper
 import android.view.MotionEvent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController
 import com.android.systemui.statusbar.commandline.CommandRegistry
@@ -40,7 +39,6 @@ import org.mockito.Mockito.`when` as whenEver
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsShellTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index ebadfc78a079c8e9472e4b4db6e6827ba8ef0d26..0c8e7a5d356af37574d5696279bb8e6e64a9ad67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -26,7 +26,6 @@ import android.view.Surface
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import com.android.systemui.util.mockito.any
@@ -50,7 +49,6 @@ private const val SENSOR_Y = 250
 private const val SENSOR_RADIUS = 10
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 0d172706b127954794f729f39d0548e14b27f54d..2d8adca04a5e61e4aef94304ba4aba8b8b2ce0fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.bouncer.domain.interactor
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
@@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AlternateBouncerInteractorTest : SysuiTestCase() {
     private lateinit var underTest: AlternateBouncerInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
index a81ca86f338d4a6b74fd3110de9baa006723b0e6..4aea4f329858e6c441b0c3eb4f9127336462486c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.bouncer.domain.interactor
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import org.junit.Before
 import org.junit.Test
@@ -29,7 +28,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class PrimaryBouncerCallbackInteractorTest : SysuiTestCase() {
     private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index cb0b74f3015d2a922ff32f2005e5fd9faca1fe3b..2018e614ba00b59e4f6f737ce60a1b40a8c5ea1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.ui.BouncerView
@@ -43,7 +42,6 @@ import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() {
     private lateinit var repository: FakeKeyguardBouncerRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 333bd214fe9a4428314825b5f306d7e623b1d883..802f8e6043fde3cf31eb374ab1ae8eb33f9263ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -50,7 +49,6 @@ import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardBouncerViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index 7fa828fbfaddd4a6b8ab0d344e688a0d50ea2c7c..3df9cbb29e4aeb17a0897983913a7fbbdae6f9c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -9,7 +9,6 @@ import android.os.UserHandle
 import android.os.UserManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.coroutines.collectLastValue
@@ -40,7 +39,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
     @Mock private lateinit var appWidgetManager: AppWidgetManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index ddf788e47bf29e775478a8a1e56a8f16fb078fb0..cdc42e09683080583ecf56d0b03179a333a324f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.communal.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.FakeCommunalRepository
 import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
@@ -37,7 +36,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class CommunalInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
index a10eb295476e965a9e5f877d55a60de25e2bed0a..41a8be9663b7b38cfe1b83c265cf28bec955d5c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
@@ -5,7 +5,6 @@ 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.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection
 import org.junit.Before
@@ -15,7 +14,6 @@ import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 781ad6b10b70e684dc8696ba031bf57c6f77c4d3..8a35ef11a3647bc9ef2478c48ef6f498260ec335 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -6,7 +6,6 @@ import android.animation.ValueAnimator
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.complication.ComplicationHostViewController
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
@@ -30,7 +29,6 @@ import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
index 21192fa11da3d511f6b56be73a79ef89083de5dc..2c6c793c97f5a7c8a147bfa29ab35a53c1015ff9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
@@ -17,7 +17,6 @@ package com.android.systemui.dreams
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -30,7 +29,6 @@ import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class DreamOverlayCallbackControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 7c36642f5417f3ba4eecf575c95cca83038371a0..2af6566e993a2d94f271ff0c160d3ba2d9d4a4d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -38,7 +38,6 @@ import androidx.test.filters.SmallTest;
 
 import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
@@ -53,7 +52,6 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
index be7638ef31e679cb2e00ae8e5a3ef51bc0c21b81..d379dc6f3dc1a12bec504f3855134dcb300f5703 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
@@ -26,7 +26,6 @@ import android.service.notification.StatusBarNotification;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
@@ -38,7 +37,6 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 8379f73402cf306bc0cd7d1d816c962d3c1664bc..e5f997257cfac9e96486b3b7f2a82302d91dd101 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -49,7 +49,6 @@ import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.ComplicationLayoutEngine;
 import com.android.systemui.dreams.complication.HideComplicationTouchHandler;
@@ -72,7 +71,6 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayServiceTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 2ef227c245c3e18214bee81e296d633898c24601..365f67b5e56607ad3e99e59733d1075ea7793571 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -29,7 +29,6 @@ import static org.mockito.Mockito.when;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.Complication;
 import com.android.systemui.flags.FeatureFlags;
@@ -48,7 +47,6 @@ import org.mockito.MockitoAnnotations;
 
 import java.util.Collection;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayStateControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
index 12cb332c7cc55ede9a29c6a4f52003b9bbfadb42..7ff345cdcf7ed9efd4aebb14d2e4373a636b75ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.verify;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -36,7 +35,6 @@ import org.mockito.MockitoAnnotations;
 import java.util.List;
 import java.util.concurrent.Executor;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayStatusBarItemsProviderTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 9566e81ed08d44bbd298527e07c1dab27108ac4e..39db2beb4c4450b5df81a83f4a29f36c0b49e215 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -46,11 +46,10 @@ import android.view.View;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.FakeLogBuffer;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -72,7 +71,6 @@ import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
index d32788df30be673b5258edf9852e33f10cc733b3..315a24bfd9457d408e8fcb22865297295c72995e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
@@ -30,7 +30,6 @@ import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.Complication;
 import com.android.systemui.dreams.DreamOverlayStateController;
@@ -49,7 +48,6 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class HideComplicationTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
index 4a7700fe1ca2f04dab1cc3dfcced1fff2e177112..e0c6ab20c6e10977f43ff7c63a48e52a8189ae36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
@@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations;
 
 import kotlinx.coroutines.CoroutineScope;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AssistantAttentionConditionTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index cd2efded7e85a581d1678e4c0740fbc0bfec2362..480754c176162cc93cc0bceebe0616729f1f7971 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -31,7 +31,6 @@ import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shared.condition.Condition;
 
@@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations;
 
 import kotlinx.coroutines.CoroutineScope;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamConditionTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index ffcaeee5259628fbc6266e868620ff3fc7913600..3d1efa59a11b64901805a90798501e20156507cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.dreams.touch;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -40,7 +41,6 @@ import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
 import com.android.systemui.dreams.touch.scrim.ScrimController;
@@ -64,7 +64,6 @@ import org.mockito.MockitoAnnotations;
 import java.util.Collections;
 import java.util.Optional;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
index ff6d97d3b380c421879132b97352b9e607942a9b..6aa821f15ab194029dbc2c714d26d3086c6634b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
@@ -27,7 +27,6 @@ import android.view.MotionEvent;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.shared.system.InputChannelCompat;
@@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations;
 
 import java.util.Optional;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ShadeTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
index da393818c6f76c23cca38400e59cee94d59b3b19..017fdbe8ac010f0d3c1995aeb1703ffe67674e12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -26,7 +26,6 @@ import android.os.PowerManager;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -38,7 +37,6 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BouncerlessScrimControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
index 81f6fe3e24d399112026b0f64520d6281e82c0ad..4ee4a60fbeaf04fef6fff50655c9d43175b2c8d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -38,7 +37,6 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ScrimManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index cfee3b8f06ea3dedfd8e0636dd74d65d208812d2..e20d3afaca53aefda076bed8e431fccb259ebb19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -23,7 +23,6 @@ import android.content.Context
 import android.content.pm.PackageManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraGestureHelper
 import com.android.systemui.settings.UserTracker
@@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CameraQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
index 49168d08795878c3583e097111ac1fcfd95c3a92..faf97517ac596c4b2ab63137a2662e64b791ec2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
@@ -26,7 +26,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.notification.EnableZenModeDialog
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
@@ -61,7 +60,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
index c85c7f6785365df274e524da985181abc846dc24..548b5646f5d4f1b2f4c616d3625315207401f9ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
@@ -17,7 +17,6 @@
 
 package com.android.systemui.keyguard.data.quickaffordance
 
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.animation.Expandable
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
 import kotlinx.coroutines.flow.Flow
@@ -25,7 +24,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.yield
 
 /** Fake implementation of a quick affordance data source. */
-@RoboPilotTest
 class FakeKeyguardQuickAffordanceConfig(
     override val key: String,
     private val pickerName: String = key,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
index c3e28ae848059123b4c86ec6e0fbb602183fb61f..4ae144c033144d1971fb0c4c5468031d1a5ab223 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
@@ -21,7 +21,6 @@ import android.content.Context
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
 import com.android.systemui.statusbar.policy.FlashlightController
@@ -42,7 +41,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index ef56a9892060755962a5f460cbf7aa1c3bf66d3f..7d68cc0a3560dd2ac80afce9f73443698d35a55f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,6 @@ package com.android.systemui.keyguard.data.quickaffordance
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
 import com.android.systemui.controls.controller.ControlsController
@@ -41,7 +40,6 @@ import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
index 4f071bd9904fda7772a144b81e0cab460db8b3c0..1e80fb69c10769ff5bb73c8845934b9ffa457049 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
@@ -23,7 +23,6 @@ import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
@@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
index bd0b71df3e5c64485c3fea85dbfae73f85c7d9df..99a01858471c0d8bb17fa3247e12924f6950e4b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
@@ -23,7 +23,6 @@ import android.content.pm.UserInfo
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.backup.BackupHelper
 import com.android.systemui.settings.FakeUserTracker
@@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
index 0797d07807b4e100d0bc9b94b37fc99c9edc0efd..a1c9f87ee7bc0bd1cb92349cb28df62f0eef4f4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
@@ -21,7 +21,6 @@ import android.content.pm.UserInfo
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
@@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
index d8c0341e1979c2211b681722e36422ed915cc570..b15352bfe6ab1ed4794716fec25618aaee6ef708 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
@@ -21,7 +21,6 @@ import android.content.Context
 import android.media.AudioManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
@@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class MuteQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 9d983b8c8943377ecea3cb77d3f09f51ca27a5db..521dea34513ed7213b4b632476b6a61597f4cf71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,6 @@ package com.android.systemui.keyguard.data.quickaffordance
 import android.content.Intent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
@@ -40,7 +39,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 613c4ce4ccef8d3b6b193890af1459b95ab08e7d..02db0d7a9a50270dcc325850ec794dff896cd26c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -24,7 +24,6 @@ import android.service.quickaccesswallet.WalletCard
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.Expandable
@@ -51,7 +50,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
index 1414bace30904af855c20f06745614ab8d2505cf..a9b9c90116365489f39d1678a33c3286c9bbee06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
@@ -21,7 +21,6 @@ import android.app.admin.DevicePolicyManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.ActivityIntentHelper
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraIntentsWrapper
 import com.android.systemui.coroutines.collectLastValue
@@ -45,7 +44,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index 944b059450c94af6b62a6858115e42cc29ff8aaa..d8cdf29284ed2fb025f23012aa9c0c98287e98b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -32,7 +32,6 @@ import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUT
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.biometrics.data.repository.FaceSensorInfo
@@ -79,7 +78,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidJUnit4::class)
 class BiometricSettingsRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 307204da17617fc16bebb91a04d20fb5a99e2061..819d08a2086e9f65efdf46bdd8f089a3cca63510 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -44,7 +44,6 @@ import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PAN
 import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
@@ -122,7 +121,6 @@ import java.io.StringWriter
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
     private lateinit var underTest: DeviceEntryFaceAuthRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index def016ad8381022d98c5d9a610a985c70b804617..a58bc52bf8e52cadf6816e63e3b4bf7d94e2db60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -22,7 +22,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.coroutines.collectLastValue
@@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
index 7eb8a26d9ab64ce3409e6adac85f8f4378aefb9e..9be5558f5cc2378c9d29ef25afc67f9137c7a8b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.shared.model.DevicePosture
@@ -39,7 +38,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DevicePostureRepositoryTest : SysuiTestCase() {
     private lateinit var underTest: DevicePostureRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
index 126b841610b4ebaaa71c49048ce09394f64a9fda..567e0a9717fcb75512b7c210aba65a7a5153cdad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
@@ -22,7 +22,6 @@ import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
@@ -56,7 +55,6 @@ import org.mockito.ArgumentMatchers.anyString
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 7983e30c66fb6d71cb0dd790b6101acafebf96d8..b9119e10b720aec960de7aaf615ab0ca7c1cde92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -22,7 +22,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.common.shared.model.Position
@@ -64,7 +63,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardRepositoryImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index 4942cf84a6fcad0d7e69f5bebeb5a7440efb1a58..799bd5ac573984a3f4ff28f61643ff6c10a00110 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -20,7 +20,6 @@ import android.graphics.Point
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.coroutines.collectLastValue
@@ -46,7 +45,6 @@ import org.junit.runner.RunWith
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class LightRevealScrimRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
index 7f784d88da6de0f51bac6a2651f040a6cd3e43fd..ee47c58f4002edb97037eb6a2109b3f6559bbb89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
@@ -21,7 +21,6 @@ import android.content.pm.UserInfo
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.logging.TrustRepositoryLogger
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.FlowValue
 import com.android.systemui.coroutines.collectLastValue
@@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class TrustRepositoryTest : SysuiTestCase() {
     @Mock private lateinit var trustManager: TrustManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 181cc884c9f5967a06074f6247c58b5db4393a50..d6e19cbcb826b55f329adfa3da5a5c4d2e4544bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardDismissActionInteractorTest : SysuiTestCase() {
     private lateinit var keyguardRepository: FakeKeyguardRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
index c407b14dcf6529f8cc6b8292d5f3fea6c4497007..a5cfbbfda196242bac2d36daaf06f9020dda5138 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
@@ -22,7 +22,6 @@ import android.service.trust.TrustAgentService
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.TrustGrantFlags
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.shared.model.DismissAction
@@ -40,7 +39,6 @@ import org.junit.runner.RunWith
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardDismissInteractorTest : SysuiTestCase() {
     private lateinit var dispatcher: TestDispatcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index b527510fc56f1dbd779ae9473c975a41a9bac794..06eb0dd364b5700bdcceccc146fcb11529acede6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -28,8 +28,10 @@ import com.android.keyguard.FaceWakeUpTriggersConfig
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FaceSensorInfo
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
 import com.android.systemui.biometrics.shared.model.LockoutMode
+import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -156,7 +158,6 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
                 fakeDeviceEntryFingerprintAuthRepository,
                 fakeUserRepository,
                 facePropertyRepository,
-                fakeKeyguardRepository,
                 faceWakeUpTriggersConfig,
                 powerInteractor,
             )
@@ -439,6 +440,43 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
                 .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER, false))
         }
 
+    @Test
+    fun faceAuthIsRequestedWhenWalletIsLaunchedAndIfFaceAuthIsStrong() =
+        testScope.runTest {
+            underTest.start()
+            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
+
+            underTest.onWalletLaunched()
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value)
+                .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED, true))
+        }
+
+    @Test
+    fun faceAuthIsNotTriggeredIfFaceAuthIsWeak() =
+        testScope.runTest {
+            underTest.start()
+            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.WEAK))
+
+            underTest.onWalletLaunched()
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
+    @Test
+    fun faceAuthIsNotTriggeredIfFaceAuthIsConvenience() =
+        testScope.runTest {
+            underTest.start()
+            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.CONVENIENCE))
+
+            underTest.onWalletLaunched()
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
     @Test
     fun faceUnlockIsDisabledWhenFpIsLockedOut() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index ca52cdb227e55fb196f0a27ef75b167d6a994d52..9ee22c89405dd943c0cc40bced0c6540ee783707 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -20,7 +20,6 @@ package com.android.systemui.keyguard.domain.interactor
 import android.app.StatusBarManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
@@ -47,7 +46,6 @@ import org.junit.runner.RunWith
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardInteractorTest : SysuiTestCase() {
 
@@ -206,7 +204,8 @@ class KeyguardInteractorTest : SysuiTestCase() {
                     fromScene = SceneKey.Gone,
                     toScene = SceneKey.Lockscreen,
                     progress = flowOf(0f),
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             assertThat(isAnimate).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 13025a016eff5b1db2bed5ac27d55f7224b71dbd..0c74a38fea0472ca400c56fdc037abefc7beeb04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -22,7 +22,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
@@ -51,7 +50,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardLongPressInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 8c13bb465103c3ffd4b32998517ee533a0cc5ba6..347d580abf5bbe79035c62d2f39c8fe52b768ce4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -23,7 +23,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogLaunchAnimator
 import com.android.systemui.common.shared.model.ContentDescription
@@ -73,7 +72,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
index fdcc66b6c97405cf606e09b82c57e6e13f80476a..71fcf6f9955c675c7486ac15223aad0392c523ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
@@ -41,7 +40,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index fa93253642e3448a3ef68534d5b657d565ffd1b8..29b546bd49adb1313104295d7c3a796ba2394533 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -42,7 +41,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardTransitionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 906d948591408d8fb9d298ed59ec7486058abae3..c02add1d0ecb0b9415dac2ab1f190197615cb389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
@@ -45,7 +44,6 @@ import org.mockito.MockitoAnnotations
 import org.mockito.Spy
 
 @SmallTest
-@RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class LightRevealScrimInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 73ecae5af9b3c715f2270b4ba3922f3c6a89d713..16f2fa22d5fba549722380129ba5f6a122757258 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -38,7 +37,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
index a22f603ae92ae7b343f389523f6ff1829aa800d3..5b29a867ceaf53d725a57467069c82a493771d0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
@@ -20,7 +20,6 @@ import android.testing.TestableLooper.RunWithLooper
 import android.view.RemoteAnimationTarget
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardViewController
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor
@@ -41,7 +40,6 @@ import org.mockito.Mockito.doAnswer
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWithLooper(setAsMainLooper = true)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardSurfaceBehindParamsApplierTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 7a17435b9165af59bcd50983d1c1a5aee419baae..9b2db3e5316cc975a9aa37621cca597bb2b693b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.binder
 import android.app.IActivityTaskManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -35,7 +34,6 @@ import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1768f8c4385b8cacda824f8b66d00b0196c88e52
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
@@ -0,0 +1,197 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+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.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+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
+
+@ExperimentalCoroutinesApi
+@RunWith(JUnit4::class)
+@SmallTest
+class AlternateBouncerViewModelTest : SysuiTestCase() {
+
+    private lateinit var testScope: TestScope
+
+    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock private lateinit var falsingManager: FalsingManager
+
+    private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var transitionInteractor: KeyguardTransitionInteractor
+    private lateinit var underTest: AlternateBouncerViewModel
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        testScope = TestScope()
+
+        val transitionInteractorWithDependencies =
+            KeyguardTransitionInteractorFactory.create(testScope.backgroundScope)
+        transitionInteractor = transitionInteractorWithDependencies.keyguardTransitionInteractor
+        transitionRepository = transitionInteractorWithDependencies.repository
+        underTest =
+            AlternateBouncerViewModel(
+                statusBarKeyguardViewManager,
+                transitionInteractor,
+                falsingManager,
+            )
+    }
+
+    @Test
+    fun transitionToAlternateBouncer_scrimAlphaUpdate() =
+        runTest(UnconfinedTestDispatcher()) {
+            val scrimAlphas by collectValues(underTest.scrimAlpha)
+
+            transitionRepository.sendTransitionStep(
+                stepToAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.4f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+
+            assertThat(scrimAlphas.size).isEqualTo(4)
+            scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+        }
+
+    @Test
+    fun transitionFromAlternateBouncer_scrimAlphaUpdate() =
+        runTest(UnconfinedTestDispatcher()) {
+            val scrimAlphas by collectValues(underTest.scrimAlpha)
+
+            transitionRepository.sendTransitionStep(
+                stepFromAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.4f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+
+            assertThat(scrimAlphas.size).isEqualTo(4)
+            scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+        }
+
+    @Test
+    fun clickListenerUpdate() =
+        runTest(UnconfinedTestDispatcher()) {
+            val clickListener by collectLastValue(underTest.onClickListener)
+
+            // keyguard state => ALTERNATE_BOUNCER
+            transitionRepository.sendTransitionStep(
+                stepToAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+            assertThat(clickListener).isNotNull()
+
+            // ALTERNATE_BOUNCER -> keyguard state
+            transitionRepository.sendTransitionStep(
+                stepFromAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            assertThat(clickListener).isNotNull()
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+            assertThat(clickListener).isNull()
+        }
+
+    @Test
+    fun forcePluginOpen() =
+        runTest(UnconfinedTestDispatcher()) {
+            val forcePluginOpen by collectLastValue(underTest.forcePluginOpen)
+            transitionRepository.sendTransitionStep(
+                stepToAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+            assertThat(forcePluginOpen).isTrue()
+
+            transitionRepository.sendTransitionStep(
+                stepFromAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+            assertThat(forcePluginOpen).isFalse()
+        }
+
+    private fun stepToAlternateBouncer(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return step(
+            from = KeyguardState.LOCKSCREEN,
+            to = KeyguardState.ALTERNATE_BOUNCER,
+            value = value,
+            transitionState = state,
+        )
+    }
+
+    private fun stepFromAlternateBouncer(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return step(
+            from = KeyguardState.ALTERNATE_BOUNCER,
+            to = KeyguardState.LOCKSCREEN,
+            value = value,
+            transitionState = state,
+        )
+    }
+
+    private fun step(
+        from: KeyguardState,
+        to: KeyguardState,
+        value: Float,
+        transitionState: TransitionState
+    ): TransitionStep {
+        return TransitionStep(
+            from = from,
+            to = to,
+            value = value,
+            transitionState = transitionState,
+            ownerName = "AlternateBouncerViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index bfc6f31c57db50644c50568e4a89baf478b12af8..6d47aed58dacf16463fcc242178f8845183a382f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -46,7 +45,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: DreamingToLockscreenTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
index 75c8bff326b0f708bc22101ad23e99a9e247098b..cf2012989624bab94ef2043078548244d206195e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: GoneToDreamingTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index 12fe07f0827ef8faa53b498efd2aff850b4b1168..89a1d2b3011d6e5d82e428309e6916b8f45d603f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: LockscreenToDreamingTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index 83ae631ed164b8b53da3535250ae0677a88963cc..41f8856d5ca2d5dbaf0f402480a8ace8ec394d95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: LockscreenToOccludedTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index 88603999cdd75f59daa6745c0c01e9bd91cad247..ec95cb8c43f10a4e5e8d519d1e184dba71905ca2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: OccludedToLockscreenTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index da372eaf158c22d2ac0d9ce2a79578c3defdf78e..93640975901bb6ec20569503d0ac0a84a1e7595a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.coroutines.collectValues
@@ -46,7 +45,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
index 9ab9b3d160d1c920a47d6c68e8a7fdcc815961d4..32acefebfa6885739d5229a1165b3b8eee249c57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
@@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations
 
 @ExperimentalCoroutinesApi
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class UdfpsAodViewModelTest : SysuiTestCase() {
     private val defaultPadding = 12
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
index 9a55f722c13cdad5bf444c27c8ac99afa11b343e..d277fcab36902c5b22d309f006380895d933aa55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.qs.pipeline.data.repository
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -39,7 +38,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AutoAddSettingsRepositoryTest : SysuiTestCase() {
     private val secureSettings = FakeSettings()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
index 30f5811c373183978481dafdcc7896c079a54bd0..3db676d68f429ec0216fd87fca9b9933123d815b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
@@ -20,7 +20,6 @@ import android.content.ComponentName
 import android.content.SharedPreferences
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.util.FakeSharedPreferences
@@ -30,7 +29,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CustomTileAddedSharedPreferencesRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
index 995de662aaf077874a57c56585fe7eb69d93f839..070e07a75d23614cfcf234b00f986cf244f537ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
@@ -32,7 +32,6 @@ import android.service.quicksettings.TileService
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.util.mockito.any
@@ -62,7 +61,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 @OptIn(ExperimentalCoroutinesApi::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt
index dc09a33adc1c0f4e7727bb4ca6597185ac7e14a0..ff8a9bd019fb2f5cb5eede054e02df88d6cb84f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt
@@ -4,7 +4,6 @@ import android.content.Intent
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.FakeBroadcastDispatcher
 import com.android.systemui.coroutines.collectLastValue
@@ -24,7 +23,6 @@ import org.mockito.MockitoAnnotations
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
-@RoboPilotTest
 class QSSettingsRestoredBroadcastRepositoryTest : SysuiTestCase() {
     private val dispatcher = StandardTestDispatcher()
     private val testScope = TestScope(dispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
index 08adebb87b1b6df8d74c204afbacbbb01c1ce64c..f7c3b213730c647517ea3a653ccb5372752a3179 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
@@ -20,7 +20,6 @@ import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -40,7 +39,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class TileSpecSettingsRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
index 20876237b476e333bd4507be2e578f20208ce793..9516c2181ac0e9aa79c7813247a862831513614c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
@@ -2,14 +2,12 @@ package com.android.systemui.qs.pipeline.data.repository
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class TilesSettingConverterTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
index 81fd72b11227906471e2bf2c2d5cd4fd4f7bc788..36e860e37ffa718aa4aac44b8f9bb889a12d61c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
@@ -3,7 +3,6 @@ package com.android.systemui.qs.pipeline.data.repository
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.data.model.RestoreData
@@ -24,7 +23,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class UserAutoAddRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
index 389580c1326b4d071c3083d5a8cbf65ca3cd2d69..d4a9fabd68067c5cc7f7c87b5aeb6ecaa8cf5507 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
@@ -3,7 +3,6 @@ package com.android.systemui.qs.pipeline.data.repository
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.data.model.RestoreData
@@ -23,7 +22,6 @@ import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
index 15e401d24b020d7d8293c02a0baf27ae4bfe6f6d..4454a3cb15fc53423752150ce354e7e34a4534c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
@@ -20,7 +20,6 @@ import android.content.ComponentName
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.util.mockito.mock
@@ -29,7 +28,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AutoAddableSettingListTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
index 7c6dd242a56992ffa4aef234c1ed9ac939e74ec4..d153e9d1d3615fa48d3d08dc2b3f9d76ab03d33b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
@@ -36,7 +35,6 @@ import org.junit.runner.RunWith
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AutoAddableSettingTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
index 469eee3638893a0abeca61a7c4abe684c8881946..ec139e4c515e5173988e32520b5a831823178a99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -36,7 +35,6 @@ import org.junit.runner.RunWith
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CallbackControllerAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
index b6eaa39222784c4c920d1204e7ea07f018293367..4fae532d417473f996bbd791a0aa0b7ff3275684 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -42,7 +41,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CastAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
index a755fbbdfd7f7a2a3881f481b3621fcd9cbcbb57..9e2d1f885e2d95ad54172968849ab6ec6a59eb16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DataSaverAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
index daacca51a915edf94383fc8f52cd5bb53ee83db7..0116bd9575d8c87c967ab42249622cc3de04bf24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DeviceControlsAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
index 4b5f7f6d07ef0475e8284d575ef7486b2d265f4e..e7ea9a66450c4106f35ad7a49e40cdb43a702946 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class HotspotAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
index 32d9db24a3b29f180613f03380baf3ec0e6c60bd..20fd3601f9efc7cedd4b37e3be4d3233a9c14185 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 import android.hardware.display.NightDisplayListener
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.NightDisplayListenerModule
@@ -50,7 +49,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class NightDisplayAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
index fb513a6bd197189423cb4bae927f0d39dd3e7d61..19ac63c36cab5f98ac301c16c71497f760d5d595 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.ReduceBrightColorsController
@@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
index 5ce15fa57b1f3f24cce451f0f483b74477483859..d645ee34619ba8f66544460a98e91f0e74228403 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
@@ -21,7 +21,6 @@ import android.content.pm.PackageManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
@@ -52,7 +51,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class SafetyCenterAutoAddableTest : SysuiTestCase() {
     private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
index 1c8cb541e613a7d9796535987e1961cd0ab00557..83ff35d8022d1f6aa73c1f10381e3474ddf47d90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -38,7 +37,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WalletAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
index de1d29fdcbe5978e15fae44c7ce53b03e6ba919b..adccc84e494baf4e0cf8d13be01aa7bbb5fe8d6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
@@ -23,7 +23,6 @@ import android.content.pm.UserInfo.FLAG_PRIMARY
 import android.content.pm.UserInfo.FLAG_PROFILE
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WorkTileAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
index bb18115c960c0fc700464f8e293cb75ef91af48d..41a7ec03408d8650c2b00b14c7557c421cc7aa7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dump.DumpManager
@@ -47,7 +46,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class AutoAddInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index a7505240caeb704977cb9fb3a71846786fd07cb5..a89338a38e890db7fe24be32c2879b6b4d5c24b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -24,7 +24,6 @@ import android.os.UserHandle
 import android.service.quicksettings.Tile
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dump.nano.SystemUIProtoDump
@@ -71,7 +70,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class CurrentTilesInteractorImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
index 151b256c4f5c23310968f173c1242e57378734ce..0d9711588a1f33403f2884e11dd5a8af99fa8f38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
@@ -17,7 +17,6 @@ package com.android.systemui.qs.pipeline.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.ShadeController
 import org.junit.Before
@@ -27,7 +26,6 @@ import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class PanelInteractorImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index 2e6b50b637dd1b978cff5de36866d129c924a2a8..f73cab8a10a3e3217260e42aaabe3b2dc5074192 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -2,7 +2,6 @@ package com.android.systemui.qs.pipeline.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.data.model.RestoreData
@@ -20,7 +19,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class RestoreReconciliationInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
index 34c4c98429862963a19354fb096b23bf0f02d6e3..558e7694b54c06d249c0f551dfaa03ec6b224860 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
@@ -19,14 +19,12 @@ package com.android.systemui.qs.pipeline.shared
 import android.content.ComponentName
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class TileSpecTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt
index 06b7a9fde873340d1a0228ff5edc2326a80ff716..5659f0173860778c4fdc684b41754e74eefbbce9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.qs.tiles.base.actions
 import android.content.Intent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
 import org.junit.Before
@@ -32,7 +31,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QSTileIntentUserActionHandlerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
index 2c4e10eadfc9726a611babed4b865a52ea34987e..9861606fd1b1b3925b874ad20d174ed66ff421cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
@@ -20,7 +20,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId
 import com.android.internal.logging.UiEventLogger
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.QSEvent
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
@@ -34,7 +33,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QSTileAnalyticsTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
index 4f25d12aea4989fe72e4e084d9262098c94a8c5d..a6199c25874b2425048d6c2644bab3915afb7b92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
@@ -24,7 +24,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.RestrictedLockUtils
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.util.mockito.any
@@ -46,7 +45,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DisabledByPolicyInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
index 4401e0d60da626dd4ff04bbf4e885fdbc84ffe41..f1fcee318141ffbf3dd609cac66dc2488919f2c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.tiles.base.logging
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
@@ -39,7 +38,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QSTileLoggerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
index 4760dfa3561d9f30a38949ae371f92eabfdba3cf..2084aeb7fe833cb172fd8255f3d60b6065a961c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
@@ -20,7 +20,6 @@ import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.android.internal.logging.InstanceId
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.common.shared.model.ContentDescription
@@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations
 
 // TODO(b/299909368): Add more tests
 @MediumTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class QSTileViewModelInterfaceComplianceTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 61dd69a8126b5bdaac92d800b3b8083f07a1fdf2..2e16577bb24fd7c232cbd8cb9ffcc10ccdcd7249 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -52,6 +52,7 @@ import com.google.common.truth.Truth.assertWithMessage
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -462,7 +463,8 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
                 fromScene = getCurrentSceneInUi(),
                 toScene = to.key,
                 progress = progressFlow,
-                isUserInputDriven = false,
+                isInitiatedByUserInput = false,
+                isUserInputOngoing = flowOf(false),
             )
         runCurrent()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 432bd0f2a0507b577b94e8de24f6ab9e497fa452..740c6d9329dfd3f73735477bcb0861e91a12814a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.scene.shared.model.SceneModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -119,7 +120,8 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
                     fromScene = SceneKey.Lockscreen,
                     toScene = SceneKey.Shade,
                     progress = progress,
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 8b23d183f1a6e5f3675a5561e7e181a342b787c7..31d26c0d88f95c3e42785974a9624872c4474a2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -83,7 +83,8 @@ class SceneInteractorTest : SysuiTestCase() {
                     fromScene = SceneKey.Lockscreen,
                     toScene = SceneKey.Shade,
                     progress = progress,
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
 
@@ -121,7 +122,8 @@ class SceneInteractorTest : SysuiTestCase() {
                     fromScene = underTest.desiredScene.value.key,
                     toScene = SceneKey.Shade,
                     progress = progress,
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             assertThat(transitionTo).isEqualTo(SceneKey.Shade)
 
@@ -158,7 +160,8 @@ class SceneInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Gone,
                         toScene = SceneKey.Lockscreen,
                         progress = flowOf(0.5f),
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             val transitioning by
@@ -177,7 +180,8 @@ class SceneInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Shade,
                         toScene = SceneKey.QuickSettings,
                         progress = flowOf(0.5f),
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             underTest.setTransitionState(transitionState)
@@ -194,7 +198,8 @@ class SceneInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Shade,
                         toScene = SceneKey.Lockscreen,
                         progress = flowOf(0.5f),
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             val transitioning by
@@ -222,7 +227,8 @@ class SceneInteractorTest : SysuiTestCase() {
                     fromScene = SceneKey.Shade,
                     toScene = SceneKey.Lockscreen,
                     progress = flowOf(0.5f),
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             assertThat(transitioning).isTrue()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 7b13de657657bc5ebd61f2fc53f4c15804ced86f..3b9621e5c6e06c6ecdb2fc3ad868296b58c44c7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -109,7 +109,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
                     fromScene = SceneKey.Gone,
                     toScene = SceneKey.Shade,
                     progress = flowOf(0.5f),
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             assertThat(isVisible).isTrue()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
@@ -122,7 +123,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
                     fromScene = SceneKey.Shade,
                     toScene = SceneKey.Gone,
                     progress = flowOf(0.5f),
-                    isUserInputDriven = false,
+                    isInitiatedByUserInput = false,
+                    isUserInputOngoing = flowOf(false),
                 )
             assertThat(isVisible).isTrue()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
index 1bb2ff8251157f0ace82df0fd82d645fdc90d54d..263b0017221a364507b34841fdc87ba57ce3e47c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -42,6 +42,7 @@ class UserTrackerImplReceiveTest : SysuiTestCase() {
         @Parameterized.Parameters
         fun data(): Iterable<String> =
             listOf(
+                Intent.ACTION_LOCALE_CHANGED,
                 Intent.ACTION_USER_INFO_CHANGED,
                 Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
                 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 52b25f85b8707698be295fbaed50cf9d6ccc0fbe..c32d2597bd61a8bd5da0851819222404b77d2189 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -177,7 +177,8 @@ class UserTrackerImplTest : SysuiTestCase() {
         verify(context)
                 .registerReceiverForAllUsers(eq(tracker), capture(captor), isNull(), eq(handler))
         with(captor.value) {
-            assertThat(countActions()).isEqualTo(6)
+            assertThat(countActions()).isEqualTo(7)
+            assertThat(hasAction(Intent.ACTION_LOCALE_CHANGED)).isTrue()
             assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
             assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
             assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index dd77da38422fd2bacddaeb2b79c27c2f4aa6b6fe..8d8c70e26ab28fa0d7f52e3d64f21f4681d0fc29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -79,7 +79,6 @@ import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
 import com.android.keyguard.logging.KeyguardLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -120,6 +119,7 @@ import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.qs.QSFragmentLegacy;
+import com.android.systemui.res.R;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.data.repository.ShadeRepository;
@@ -153,7 +153,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
@@ -170,6 +169,7 @@ import com.android.systemui.statusbar.phone.TapAgainViewController;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
@@ -182,6 +182,8 @@ import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.time.SystemClock;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
+import dagger.Lazy;
+
 import org.junit.After;
 import org.junit.Before;
 import org.mockito.ArgumentCaptor;
@@ -193,7 +195,6 @@ import org.mockito.stubbing.Answer;
 import java.util.List;
 import java.util.Optional;
 
-import dagger.Lazy;
 import kotlinx.coroutines.CoroutineDispatcher;
 
 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
@@ -208,7 +209,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
     @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
     @Mock protected ViewPropertyAnimator mViewPropertyAnimator;
     @Mock protected KeyguardBottomAreaView mQsFrame;
-    @Mock protected HeadsUpManagerPhone mHeadsUpManager;
+    @Mock protected HeadsUpManager mHeadsUpManager;
     @Mock protected NotificationShelfController mNotificationShelfController;
     @Mock protected NotificationGutsManager mGutsManager;
     @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
@@ -527,7 +528,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
         NotificationWakeUpCoordinator coordinator =
                 new NotificationWakeUpCoordinator(
                         mDumpManager,
-                        mock(HeadsUpManagerPhone.class),
+                        mock(HeadsUpManager.class),
                         new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
                                 mInteractionJankMonitor, mShadeExpansionStateManager),
                         mKeyguardBypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 2ed20908ba2fdeae8a8c79af47fca10256a87b1c..eb006100d5356d15a032193d682614a8826ae2a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -47,18 +47,34 @@ import android.view.WindowManager;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.KeyguardSecurityModel;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.FakeWindowRootViewComponent;
 import com.android.systemui.scene.SceneTestUtils;
+import com.android.systemui.scene.data.repository.SceneContainerRepository;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
+import com.android.systemui.scene.shared.logger.SceneLogger;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.StatusBarState;
@@ -71,9 +87,9 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.user.domain.interactor.UserInteractor;
 
 import com.google.common.util.concurrent.MoreExecutors;
@@ -109,6 +125,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock ColorExtractor.GradientColors mGradientColors;
     @Mock private DumpManager mDumpManager;
+    @Mock private KeyguardSecurityModel mKeyguardSecurityModel;
     @Mock private KeyguardStateController mKeyguardStateController;
     @Mock private ScreenOffAnimationController mScreenOffAnimationController;
     @Mock private AuthController mAuthController;
@@ -123,6 +140,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
 
     private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
     private float mPreferredRefreshRate = -1;
+    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor;
+    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;
 
     @Before
     public void setUp() {
@@ -137,22 +156,86 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
+        FakeKeyguardRepository keyguardRepository = new FakeKeyguardRepository();
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        FakeShadeRepository shadeRepository = new FakeShadeRepository();
+        FakePowerRepository powerRepository = new FakePowerRepository();
+
+        PowerInteractor powerInteractor = new PowerInteractor(
+                powerRepository,
+                new FalsingCollectorFake(),
+                mScreenOffAnimationController,
+                mStatusBarStateController);
+
+        SceneInteractor sceneInteractor = new SceneInteractor(
+                mTestScope.getBackgroundScope(),
+                new SceneContainerRepository(
+                        mTestScope.getBackgroundScope(),
+                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+                powerRepository,
+                mock(SceneLogger.class));
+
+        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
+        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
+                keyguardRepository,
+                new FakeCommandQueue(),
+                powerInteractor,
+                featureFlags,
+                sceneContainerFlags,
+                new FakeDeviceEntryRepository(),
+                new FakeKeyguardBouncerRepository(),
+                configurationRepository,
+                shadeRepository,
+                () -> sceneInteractor);
+
+        FakeKeyguardTransitionRepository keyguardTransitionRepository =
+                new FakeKeyguardTransitionRepository();
+
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                new KeyguardTransitionInteractor(
+                        mTestScope.getBackgroundScope(),
+                        keyguardTransitionRepository,
+                        () -> keyguardInteractor,
+                        () -> mFromLockscreenTransitionInteractor,
+                        () -> mFromPrimaryBouncerTransitionInteractor);
+
+        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                shadeRepository,
+                powerInteractor);
+
+        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mKeyguardSecurityModel,
+                powerInteractor);
+
         mShadeInteractor =
                 new ShadeInteractor(
                         mTestScope.getBackgroundScope(),
+                        new FakeDeviceProvisioningRepository(),
                         new FakeDisableFlagsRepository(),
-                        new FakeSceneContainerFlags(),
-                        mUtils::sceneInteractor,
-                        new FakeKeyguardRepository(),
+                        mock(DozeParameters.class),
+                        sceneContainerFlags,
+                        () -> sceneInteractor,
+                        keyguardRepository,
+                        keyguardTransitionInteractor,
+                        powerInteractor,
                         new FakeUserSetupRepository(),
-                        mock(DeviceProvisionedController.class),
                         mock(UserInteractor.class),
                         new SharedNotificationContainerInteractor(
-                                new FakeConfigurationRepository(),
+                                configurationRepository,
                                 mContext,
                                 new ResourcesSplitShadeStateController()),
-                        new FakeShadeRepository()
-                );
+                        shadeRepository);
 
         mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
                 mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index add1580f25a56d0cf09da48f6c5e6d0f0c20fd31..b4f9e8dcfb397957862005fe0bf4410813bede53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.back.domain.interactor.BackActionInteractor
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
 import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -144,6 +145,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
     @Mock
     lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
     @Mock lateinit var keyEventInteractor: KeyEventInteractor
+    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
     private val notificationExpansionRepository = NotificationExpansionRepository()
 
     private lateinit var fakeClock: FakeSystemClock
@@ -176,6 +179,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
         featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
         featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
         featureFlags.set(Flags.MIGRATE_NSSL, false)
+        featureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false)
 
         testScope = TestScope()
         fakeClock = FakeSystemClock()
@@ -248,6 +252,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
                 ),
                 BouncerLogger(logcatLogBuffer("BouncerLog")),
                 keyEventInteractor,
+                primaryBouncerInteractor,
+                alternateBouncerInteractor,
             )
         underTest.setupExpandedStatusBar()
         underTest.setDragDownHelper(dragDownHelper)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 00230202d9412b287cf8b54c8205f20031b60acd..189c9e25d9b0368ec9cbe834961a69a8a9b00be7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -33,6 +33,7 @@ import com.android.systemui.back.domain.interactor.BackActionInteractor
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
 import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -141,6 +142,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
         Optional<UnfoldTransitionProgressProvider>
     @Mock private lateinit var notificationInsetsController: NotificationInsetsController
     @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
     @Mock
     private lateinit var primaryBouncerToGoneTransitionViewModel:
         PrimaryBouncerToGoneTransitionViewModel
@@ -180,6 +183,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
         featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
         featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
         featureFlags.set(Flags.MIGRATE_NSSL, false)
+        featureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false)
         testScope = TestScope()
         controller =
             NotificationShadeWindowViewController(
@@ -250,6 +254,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                 ),
                 BouncerLogger(logcatLogBuffer("BouncerLog")),
                 Mockito.mock(KeyEventInteractor::class.java),
+                primaryBouncerInteractor,
+                alternateBouncerInteractor,
             )
 
         controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 8138b328a3c51f08182473d58af90a82ac53a6b0..65174bab7f638e6106a50e34cb8b5ef45467b74c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -32,23 +32,39 @@ import android.view.accessibility.AccessibilityManager;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.media.controls.pipeline.MediaDataManager;
 import com.android.systemui.media.controls.ui.MediaHierarchyManager;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.qs.QSFragmentLegacy;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.SceneTestUtils;
+import com.android.systemui.scene.data.repository.SceneContainerRepository;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
+import com.android.systemui.scene.shared.logger.SceneLogger;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
@@ -64,19 +80,21 @@ import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFl
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
 import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.user.domain.interactor.UserInteractor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
@@ -103,8 +121,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
     protected SceneTestUtils mUtils = new SceneTestUtils(this);
     protected TestScope mTestScope = mUtils.getTestScope();
 
-    @Mock
-    protected Resources mResources;
+    @Mock protected Resources mResources;
     @Mock protected KeyguardBottomAreaView mQsFrame;
     @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
     @Mock protected QS mQs;
@@ -126,6 +143,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
     @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
     @Mock protected ShadeHeaderController mShadeHeaderController;
     @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock protected DozeParameters mDozeParameters;
     @Mock protected KeyguardStateController mKeyguardStateController;
     @Mock protected KeyguardBypassController mKeyguardBypassController;
     @Mock protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -144,7 +162,6 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
     @Mock protected DumpManager mDumpManager;
     @Mock protected UiEventLogger mUiEventLogger;
     @Mock protected CastController mCastController;
-    @Mock protected DeviceProvisionedController mDeviceProvisionedController;
     @Mock protected UserInteractor mUserInteractor;
     protected FakeDisableFlagsRepository mDisableFlagsRepository =
             new FakeDisableFlagsRepository();
@@ -161,6 +178,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
             new ShadeExpansionStateManager();
 
     protected FragmentHostManager.FragmentListener mFragmentListener;
+    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor;
+    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;
 
     @Before
     public void setup() {
@@ -169,21 +188,89 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
                 mInteractionJankMonitor, mShadeExpansionStateManager);
 
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+        FakeDeviceProvisioningRepository deviceProvisioningRepository =
+                new FakeDeviceProvisioningRepository();
+        deviceProvisioningRepository.setDeviceProvisioned(true);
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        FakePowerRepository powerRepository = new FakePowerRepository();
+        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
+
+        PowerInteractor powerInteractor = new PowerInteractor(
+                powerRepository,
+                new FalsingCollectorFake(),
+                mock(ScreenOffAnimationController.class),
+                mStatusBarStateController);
+
+        SceneInteractor sceneInteractor = new SceneInteractor(
+                mTestScope.getBackgroundScope(),
+                new SceneContainerRepository(
+                        mTestScope.getBackgroundScope(),
+                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+                powerRepository,
+                mock(SceneLogger.class));
+
+        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
+                mKeyguardRepository,
+                new FakeCommandQueue(),
+                powerInteractor,
+                featureFlags,
+                sceneContainerFlags,
+                new FakeDeviceEntryRepository(),
+                new FakeKeyguardBouncerRepository(),
+                configurationRepository,
+                mShadeRepository,
+                () -> sceneInteractor);
+
+        FakeKeyguardTransitionRepository keyguardTransitionRepository =
+                new FakeKeyguardTransitionRepository();
+
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                new KeyguardTransitionInteractor(
+                        mTestScope.getBackgroundScope(),
+                        keyguardTransitionRepository,
+                        () -> keyguardInteractor,
+                        () -> mFromLockscreenTransitionInteractor,
+                        () -> mFromPrimaryBouncerTransitionInteractor);
+
+        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mShadeRepository,
+                powerInteractor);
+
+        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mock(KeyguardSecurityModel.class),
+                powerInteractor);
+
+        ResourcesSplitShadeStateController splitShadeStateController =
+                new ResourcesSplitShadeStateController();
+
         mShadeInteractor =
                 new ShadeInteractor(
                         mTestScope.getBackgroundScope(),
+                        deviceProvisioningRepository,
                         mDisableFlagsRepository,
-                        new FakeSceneContainerFlags(),
-                        () -> mUtils.sceneInteractor(),
+                        mDozeParameters,
+                        sceneContainerFlags,
+                        () -> sceneInteractor,
                         mKeyguardRepository,
+                        keyguardTransitionInteractor,
+                        powerInteractor,
                         new FakeUserSetupRepository(),
-                        mDeviceProvisionedController,
                         mUserInteractor,
                         new SharedNotificationContainerInteractor(
-                                new FakeConfigurationRepository(),
+                                configurationRepository,
                                 mContext,
-                                new ResourcesSplitShadeStateController()),
+                                splitShadeStateController),
                         mShadeRepository
                 );
 
@@ -262,7 +349,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
                 mShadeInteractor,
                 new JavaAdapter(mTestScope.getBackgroundScope()),
                 mCastController,
-                new ResourcesSplitShadeStateController()
+                splitShadeStateController
         );
         mQsController.init();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index b5841a9de150452ea76f5ace3b0933c409a6404e..215f8b1c462f7b29b2d980c8fdc41fa120a51e20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.shade
 
 import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
 import android.view.Display
 import android.view.WindowManager
 import androidx.test.filters.SmallTest
@@ -54,6 +55,7 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class ShadeControllerImplTest : SysuiTestCase() {
     private val executor = FakeExecutor(FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index 2be1c09843c104caa5f7c9c357ef154fe0cff752..bcb060ddb41752b29bf6bd7c3483ea97d7f91281 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -16,50 +16,53 @@
 
 package com.android.systemui.shade.data.repository
 
-import android.app.ActivityManager
 import android.app.StatusBarManager.DISABLE2_NONE
 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
 import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
 import android.content.pm.UserInfo
 import android.os.UserManager
 import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.SysUITestModule
+import com.android.TestMocksModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.power.data.repository.FakePowerRepository
+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.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
-import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
 import com.android.systemui.user.data.model.UserSwitcherSettingsModel
 import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.GuestUserInteractor
-import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
-import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
-import com.android.systemui.user.domain.interactor.UserInteractor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.domain.UserDomainLayerModule
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -70,50 +73,55 @@ import org.mockito.MockitoAnnotations
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 class ShadeInteractorTest : SysuiTestCase() {
-    private lateinit var underTest: ShadeInteractor
 
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
-    private val featureFlags = FakeFeatureFlags()
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val userRepository = FakeUserRepository()
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val shadeRepository = FakeShadeRepository()
-    private val configurationRepository = FakeConfigurationRepository()
-    private val sharedNotificationContainerInteractor =
-        SharedNotificationContainerInteractor(
-            configurationRepository,
-            mContext,
-            ResourcesSplitShadeStateController()
-        )
-
-    @Mock private lateinit var manager: UserManager
-    @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
-    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock private lateinit var activityStarter: ActivityStarter
-    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
-    @Mock private lateinit var activityManager: ActivityManager
-    @Mock private lateinit var uiEventLogger: UiEventLogger
-    @Mock private lateinit var guestInteractor: GuestUserInteractor
-
-    private lateinit var userInteractor: UserInteractor
+    @Mock private lateinit var dozeParameters: DozeParameters
+
+    private lateinit var testComponent: TestComponent
+
+    private val configurationRepository
+        get() = testComponent.configurationRepository
+    private val deviceProvisioningRepository
+        get() = testComponent.deviceProvisioningRepository
+    private val disableFlagsRepository
+        get() = testComponent.disableFlagsRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val keyguardTransitionRepository
+        get() = testComponent.keygaurdTransitionRepository
+    private val powerRepository
+        get() = testComponent.powerRepository
+    private val sceneInteractor
+        get() = testComponent.sceneInteractor
+    private val shadeRepository
+        get() = testComponent.shadeRepository
+    private val testScope
+        get() = testComponent.testScope
+    private val userRepository
+        get() = testComponent.userRepository
+    private val userSetupRepository
+        get() = testComponent.userSetupRepository
+
+    private lateinit var underTest: ShadeInteractor
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
-        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
-
-        val refreshUsersScheduler =
-            RefreshUsersScheduler(
-                applicationScope = testScope.backgroundScope,
-                mainDispatcher = utils.testDispatcher,
-                repository = userRepository,
-            )
+        testComponent =
+            DaggerShadeInteractorTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FACE_AUTH_REFACTOR, false)
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            dozeParameters = dozeParameters,
+                        ),
+                )
+        underTest = testComponent.underTest
 
         runBlocking {
             val userInfos =
@@ -131,44 +139,6 @@ class ShadeInteractorTest : SysuiTestCase() {
             userRepository.setUserInfos(userInfos)
             userRepository.setSelectedUserInfo(userInfos[0])
         }
-        userInteractor =
-            UserInteractor(
-                applicationContext = context,
-                repository = userRepository,
-                activityStarter = activityStarter,
-                keyguardInteractor =
-                    KeyguardInteractorFactory.create(featureFlags = featureFlags)
-                        .keyguardInteractor,
-                featureFlags = featureFlags,
-                manager = manager,
-                headlessSystemUserMode = headlessSystemUserMode,
-                applicationScope = testScope.backgroundScope,
-                telephonyInteractor =
-                    TelephonyInteractor(
-                        repository = FakeTelephonyRepository(),
-                    ),
-                broadcastDispatcher = fakeBroadcastDispatcher,
-                keyguardUpdateMonitor = keyguardUpdateMonitor,
-                backgroundDispatcher = utils.testDispatcher,
-                activityManager = activityManager,
-                refreshUsersScheduler = refreshUsersScheduler,
-                guestUserInteractor = guestInteractor,
-                uiEventLogger = uiEventLogger,
-                userRestrictionChecker = mock(),
-            )
-        underTest =
-            ShadeInteractor(
-                testScope.backgroundScope,
-                disableFlagsRepository,
-                sceneContainerFlags,
-                { sceneInteractor },
-                keyguardRepository,
-                userSetupRepository,
-                deviceProvisionedController,
-                userInteractor,
-                sharedNotificationContainerInteractor,
-                shadeRepository,
-            )
     }
 
     @Test
@@ -188,7 +158,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_deviceNotProvisioned_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+            deviceProvisioningRepository.setDeviceProvisioned(false)
 
             val actual by collectLastValue(underTest.isExpandToQsEnabled)
 
@@ -198,7 +168,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
 
             userSetupRepository.setUserSetup(false)
             userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true))
@@ -211,7 +181,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_shadeNotEnabled_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
 
             disableFlagsRepository.disableFlags.value =
@@ -227,7 +197,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
 
             disableFlagsRepository.disableFlags.value =
@@ -242,7 +212,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_dozing_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -259,7 +229,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_userSetup_true() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -276,7 +246,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -293,7 +263,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_respondsToDozingUpdates() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -321,7 +291,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_respondsToDisableUpdates() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -353,7 +323,7 @@ class ShadeInteractorTest : SysuiTestCase() {
     @Test
     fun isExpandToQsEnabled_respondsToUserUpdates() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -625,7 +595,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Lockscreen,
                         toScene = key,
                         progress = progress,
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -662,7 +633,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = key,
                         toScene = SceneKey.Lockscreen,
                         progress = progress,
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -698,7 +670,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Lockscreen,
                         toScene = SceneKey.Shade,
                         progress = progress,
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -974,7 +947,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Lockscreen,
                         toScene = key,
                         progress = progress,
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1011,7 +985,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = SceneKey.Lockscreen,
                         toScene = key,
                         progress = progress,
-                        isUserInputDriven = true,
+                        isInitiatedByUserInput = true,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1048,7 +1023,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = key,
                         toScene = SceneKey.Lockscreen,
                         progress = progress,
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1085,7 +1061,8 @@ class ShadeInteractorTest : SysuiTestCase() {
                         fromScene = key,
                         toScene = SceneKey.Lockscreen,
                         progress = progress,
-                        isUserInputDriven = true,
+                        isInitiatedByUserInput = true,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1120,8 +1097,9 @@ class ShadeInteractorTest : SysuiTestCase() {
                     ObservableTransitionState.Transition(
                         fromScene = SceneKey.Lockscreen,
                         toScene = SceneKey.QuickSettings,
-                        progress = progress,
-                        isUserInputDriven = true,
+                        progress = MutableStateFlow(0f),
+                        isInitiatedByUserInput = true,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1129,4 +1107,168 @@ class ShadeInteractorTest : SysuiTestCase() {
             // THEN interacting is false
             assertThat(interacting).isFalse()
         }
+
+    @Test
+    fun isShadeTouchable_isFalse_whenFrpIsActive() =
+        testScope.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isFalse()
+        }
+
+    @Test
+    fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == false
+            // TODO: remove?
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.LOCKSCREEN,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isFalse()
+        }
+
+    @Test
+    fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == false
+            // TODO: remove?
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.LOCKSCREEN,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isTrue()
+        }
+
+    @Test
+    fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == true
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(false)
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isFalse()
+        }
+
+    @Test
+    fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == true
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(true)
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isTrue()
+        }
+
+    @Test
+    fun isShadeTouchable_isTrue_whenNotAsleep() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isTrue()
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: ShadeInteractor
+
+        val configurationRepository: FakeConfigurationRepository
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val disableFlagsRepository: FakeDisableFlagsRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keygaurdTransitionRepository: FakeKeyguardTransitionRepository
+        val powerRepository: FakePowerRepository
+        val sceneInteractor: SceneInteractor
+        val shadeRepository: FakeShadeRepository
+        val testScope: TestScope
+        val userRepository: FakeUserRepository
+        val userSetupRepository: FakeUserSetupRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index 7463e65d1d6fa38c6b57276d400a8865a62e6a84..6eeafefd0ac19e6d91f9d9cba0e23911f969a19d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.shade.data.repository
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
@@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class ShadeRepositoryImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index 607cdab12f56b72cc3e19d4d3fc25fe404344010..bb20d94e7d3928be20a43facc2c91a1cca6d1bd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -17,6 +17,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnec
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -84,7 +85,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
                         fromScene = SceneKey.Shade,
                         toScene = SceneKey.QuickSettings,
                         progress = MutableStateFlow(0.5f),
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             )
@@ -102,7 +104,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
                         fromScene = SceneKey.QuickSettings,
                         toScene = SceneKey.Shade,
                         progress = MutableStateFlow(0.5f),
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             )
@@ -120,7 +123,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
                         fromScene = SceneKey.Gone,
                         toScene = SceneKey.Shade,
                         progress = MutableStateFlow(0.5f),
-                        isUserInputDriven = false,
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
                     )
                 )
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index e714736812115b462ef89bb49ddcad3d3382a4c1..ae659f4d26769f2438f1d21502d73296aad6cf87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -131,11 +131,10 @@ class ClockRegistryTest : SysuiTestCase() {
 
         fun addClock(
             id: ClockId,
-            name: String,
             create: (ClockId) -> ClockController = ::failFactory,
             getThumbnail: (ClockId) -> Drawable? = ::failThumbnail
         ): FakeClockPlugin {
-            metadata.add(ClockMetadata(id, name))
+            metadata.add(ClockMetadata(id))
             createCallbacks[id] = create
             thumbnailCallbacks[id] = getThumbnail
             return this
@@ -149,7 +148,7 @@ class ClockRegistryTest : SysuiTestCase() {
         scope = TestScope(dispatcher)
 
         fakeDefaultProvider = FakeClockPlugin()
-            .addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail })
+            .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail })
         whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
 
         val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>()
@@ -183,13 +182,13 @@ class ClockRegistryTest : SysuiTestCase() {
     @Test
     fun pluginRegistration_CorrectState() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = FakeLifecycle("1", plugin1)
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3")
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3")
+            .addClock("clock_4")
         val lifecycle2 = FakeLifecycle("2", plugin2)
 
         pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
@@ -198,11 +197,11 @@ class ClockRegistryTest : SysuiTestCase() {
         assertEquals(
             list.toSet(),
             setOf(
-                ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                ClockMetadata("clock_1", "clock 1"),
-                ClockMetadata("clock_2", "clock 2"),
-                ClockMetadata("clock_3", "clock 3"),
-                ClockMetadata("clock_4", "clock 4")
+                ClockMetadata(DEFAULT_CLOCK_ID),
+                ClockMetadata("clock_1"),
+                ClockMetadata("clock_2"),
+                ClockMetadata("clock_3"),
+                ClockMetadata("clock_4")
             )
         )
     }
@@ -216,13 +215,13 @@ class ClockRegistryTest : SysuiTestCase() {
     @Test
     fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
-            .addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail })
+            .addClock("clock_1", { mockClock }, { mockThumbnail })
+            .addClock("clock_2", { mockClock }, { mockThumbnail })
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
@@ -231,9 +230,9 @@ class ClockRegistryTest : SysuiTestCase() {
         assertEquals(
             list.toSet(),
             setOf(
-                ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                ClockMetadata("clock_1", "clock 1"),
-                ClockMetadata("clock_2", "clock 2")
+                ClockMetadata(DEFAULT_CLOCK_ID),
+                ClockMetadata("clock_1"),
+                ClockMetadata("clock_2")
             )
         )
 
@@ -248,13 +247,13 @@ class ClockRegistryTest : SysuiTestCase() {
     @Test
     fun createCurrentClock_pluginConnected() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3", { mockClock })
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3", { mockClock })
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
@@ -268,13 +267,13 @@ class ClockRegistryTest : SysuiTestCase() {
     @Test
     fun activeClockId_changeAfterPluginConnected() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3", { mockClock })
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3", { mockClock })
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
@@ -289,13 +288,13 @@ class ClockRegistryTest : SysuiTestCase() {
     @Test
     fun createDefaultClock_pluginDisconnected() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3")
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3")
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
@@ -310,13 +309,13 @@ class ClockRegistryTest : SysuiTestCase() {
     @Test
     fun pluginRemoved_clockAndListChanged() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3", { mockClock })
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3", { mockClock })
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         var changeCallCount = 0
@@ -415,13 +414,13 @@ class ClockRegistryTest : SysuiTestCase() {
 
     @Test
     fun pluginAddRemove_concurrentModification() {
-        val plugin1 = FakeClockPlugin().addClock("clock_1", "clock 1")
+        val plugin1 = FakeClockPlugin().addClock("clock_1")
         val lifecycle1 = FakeLifecycle("1", plugin1)
-        val plugin2 = FakeClockPlugin().addClock("clock_2", "clock 2")
+        val plugin2 = FakeClockPlugin().addClock("clock_2")
         val lifecycle2 = FakeLifecycle("2", plugin2)
-        val plugin3 = FakeClockPlugin().addClock("clock_3", "clock 3")
+        val plugin3 = FakeClockPlugin().addClock("clock_3")
         val lifecycle3 = FakeLifecycle("3", plugin3)
-        val plugin4 = FakeClockPlugin().addClock("clock_4", "clock 4")
+        val plugin4 = FakeClockPlugin().addClock("clock_4")
         val lifecycle4 = FakeLifecycle("4", plugin4)
 
         // Set the current clock to the final clock to load
@@ -450,10 +449,10 @@ class ClockRegistryTest : SysuiTestCase() {
 
         // Verify all plugins were correctly loaded into the registry
         assertEquals(registry.getClocks().toSet(), setOf(
-            ClockMetadata("DEFAULT", "Default Clock"),
-            ClockMetadata("clock_2", "clock 2"),
-            ClockMetadata("clock_3", "clock 3"),
-            ClockMetadata("clock_4", "clock 4")
+            ClockMetadata("DEFAULT"),
+            ClockMetadata("clock_2"),
+            ClockMetadata("clock_3"),
+            ClockMetadata("clock_4")
         ))
     }
 
@@ -527,8 +526,8 @@ class ClockRegistryTest : SysuiTestCase() {
         featureFlags.set(TRANSIT_CLOCK, flag)
         registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK)
         val plugin = FakeClockPlugin()
-                .addClock("clock_1", "clock 1")
-                .addClock("DIGITAL_CLOCK_METRO", "metro clock")
+                .addClock("clock_1")
+                .addClock("DIGITAL_CLOCK_METRO")
         val lifecycle = FakeLifecycle("metro", plugin)
         pluginListener.onPluginLoaded(plugin, mockContext, lifecycle)
 
@@ -536,17 +535,17 @@ class ClockRegistryTest : SysuiTestCase() {
         if (flag) {
             assertEquals(
                     setOf(
-                            ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                            ClockMetadata("clock_1", "clock 1"),
-                            ClockMetadata("DIGITAL_CLOCK_METRO", "metro clock")
+                            ClockMetadata(DEFAULT_CLOCK_ID),
+                            ClockMetadata("clock_1"),
+                            ClockMetadata("DIGITAL_CLOCK_METRO")
                     ),
                     list.toSet()
             )
         } else {
             assertEquals(
                     setOf(
-                            ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                            ClockMetadata("clock_1", "clock 1")
+                            ClockMetadata(DEFAULT_CLOCK_ID),
+                            ClockMetadata("clock_1")
                     ),
                     list.toSet()
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
index 7a2d12269885667b3ba9a64639e9998f4aaf820b..b8fe2f911b5004a48e3700c252d65561f32a9da3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.smartspace
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -33,7 +32,6 @@ import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class BcSmartspaceConfigProviderTest : SysuiTestCase() {
     @Mock private lateinit var featureFlags: FeatureFlags
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index f1c181fb22355f0c2861c9ae1d172a222e97ba79..e093859349913f627d9de77d54de83d2d42da960 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -26,7 +26,6 @@ import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dreams.smartspace.DreamSmartspaceController
 import com.android.systemui.plugins.BcSmartspaceConfigPlugin
@@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations
 import org.mockito.Spy
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class DreamSmartspaceControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
index 7af29ba28df16129c4653ce422adf572c66e3490..886c61ae29dd751a0ae8440e27b12b0b3cc866d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
@@ -25,7 +25,6 @@ import android.provider.Settings
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter
@@ -52,7 +51,6 @@ import org.mockito.MockitoAnnotations
 
 @SmallTest
 @TestableLooper.RunWithLooper
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class LockscreenAndDreamTargetFilterTest : SysuiTestCase() {
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
index a7c223dc4b8a8e41c52329e12b8dce2797917582..0b5aea7d868391cdee8f793515ff2afac9d56d93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.smartspace
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -36,7 +35,6 @@ import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class LockscreenPreconditionTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 14e58e5f570a34d10c7ad21b7c24d143862ee015..e8923a5baca88ea52dae6845443e76b300680eb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -5,41 +5,32 @@ import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
 import com.android.systemui.ExpandHelper
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
 import com.android.systemui.media.controls.ui.MediaHierarchyManager
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QS
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeViewController
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
-import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
 import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
 import com.android.systemui.statusbar.policy.FakeConfigurationController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.domain.UserDomainLayerModule
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import org.junit.After
 import org.junit.Assert.assertFalse
@@ -60,9 +51,8 @@ import org.mockito.Mockito
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 private fun <T> anyObject(): T {
     return Mockito.anyObject<T>()
@@ -73,68 +63,38 @@ private fun <T> anyObject(): T {
 @RunWith(AndroidTestingRunner::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
 
-    lateinit var transitionController: LockscreenShadeTransitionController
+    private lateinit var testComponent: TestComponent
+
+    private val transitionController
+        get() = testComponent.transitionController
+    private val configurationController
+        get() = testComponent.configurationController
+    private val disableFlagsRepository
+        get() = testComponent.disableFlagsRepository
+    private val testScope
+        get() = testComponent.testScope
+
     lateinit var row: ExpandableNotificationRow
-    @Mock lateinit var statusbarStateController: SysuiStatusBarStateController
-    @Mock lateinit var logger: LSShadeTransitionLogger
-    @Mock lateinit var dumpManager: DumpManager
+
+    @Mock lateinit var centralSurfaces: CentralSurfaces
+    @Mock lateinit var depthController: NotificationShadeDepthController
+    @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
     @Mock lateinit var keyguardBypassController: KeyguardBypassController
     @Mock lateinit var lockScreenUserManager: NotificationLockscreenUserManager
-    @Mock lateinit var falsingCollector: FalsingCollector
-    @Mock lateinit var ambientState: AmbientState
-    @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle
     @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager
+    @Mock lateinit var nsslController: NotificationStackScrollLayoutController
+    @Mock lateinit var qS: QS
     @Mock lateinit var scrimController: ScrimController
-    @Mock lateinit var falsingManager: FalsingManager
     @Mock lateinit var shadeViewController: ShadeViewController
-    @Mock lateinit var nsslController: NotificationStackScrollLayoutController
-    @Mock lateinit var depthController: NotificationShadeDepthController
     @Mock lateinit var stackscroller: NotificationStackScrollLayout
-    @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
-    @Mock lateinit var mCentralSurfaces: CentralSurfaces
-    @Mock lateinit var qS: QS
-    @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
-    @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
-    @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
-    @Mock lateinit var activityStarter: ActivityStarter
+    @Mock lateinit var statusbarStateController: SysuiStatusBarStateController
     @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val configurationRepository = FakeConfigurationRepository()
-    private val sharedNotificationContainerInteractor = SharedNotificationContainerInteractor(
-        configurationRepository,
-        mContext,
-            ResourcesSplitShadeStateController()
-    )
-    private val shadeInteractor =
-        ShadeInteractor(
-            testScope.backgroundScope,
-            disableFlagsRepository,
-            sceneContainerFlags,
-            { sceneInteractor },
-            keyguardRepository,
-            userSetupRepository = FakeUserSetupRepository(),
-            deviceProvisionedController = mock(),
-            userInteractor = mock(),
-            sharedNotificationContainerInteractor,
-            repository = FakeShadeRepository(),
-        )
-    private val powerInteractor = PowerInteractorFactory.create().powerInteractor
-    @JvmField @Rule val mockito = MockitoJUnit.rule()
 
-    private val configurationController = FakeConfigurationController()
+    @JvmField @Rule val mockito = MockitoJUnit.rule()
 
     @Before
     fun setup() {
-        // By default, have the shade enabled
-        disableFlagsRepository.disableFlags.value = DisableFlagsModel()
-        testScope.runCurrent()
-
         val helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
         row = helper.createRow()
         context
@@ -143,55 +103,9 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
         context
             .getOrCreateTestableResources()
             .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
-        transitionController =
-            LockscreenShadeTransitionController(
-                statusBarStateController = statusbarStateController,
-                logger = logger,
-                keyguardBypassController = keyguardBypassController,
-                lockScreenUserManager = lockScreenUserManager,
-                falsingCollector = falsingCollector,
-                ambientState = ambientState,
-                mediaHierarchyManager = mediaHierarchyManager,
-                depthController = depthController,
-                wakefulnessLifecycle = wakefulnessLifecycle,
-                context = context,
-                configurationController = configurationController,
-                falsingManager = falsingManager,
-                dumpManager = dumpManager,
-                splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
-                singleShadeOverScrollerFactory = { singleShadeOverScroller },
-                scrimTransitionController =
-                    LockscreenShadeScrimTransitionController(
-                        scrimController,
-                        context,
-                        configurationController,
-                        dumpManager,
-                            ResourcesSplitShadeStateController()
-                    ),
-                keyguardTransitionControllerFactory = { notificationPanelController ->
-                    LockscreenShadeKeyguardTransitionController(
-                        mediaHierarchyManager,
-                        notificationPanelController,
-                        context,
-                        configurationController,
-                        dumpManager,
-                            ResourcesSplitShadeStateController()
-                    )
-                },
-                qsTransitionControllerFactory = { qsTransitionController },
-                activityStarter = activityStarter,
-                shadeRepository = FakeShadeRepository(),
-                shadeInteractor = shadeInteractor,
-                powerInteractor = powerInteractor,
-                splitShadeStateController = ResourcesSplitShadeStateController()
-            )
-        transitionController.addCallback(transitionControllerCallback)
+
         whenever(nsslController.view).thenReturn(stackscroller)
         whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
-        transitionController.shadeViewController = shadeViewController
-        transitionController.centralSurfaces = mCentralSurfaces
-        transitionController.qS = qS
-        transitionController.setStackScroller(nsslController)
         whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         whenever(nsslController.isInLockedDownShade).thenReturn(false)
         whenever(qS.isFullyCollapsed).thenReturn(true)
@@ -199,9 +113,36 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
             .thenReturn(true)
         whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
         whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
-        whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
         whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
-        clearInvocations(mCentralSurfaces)
+
+        testComponent =
+            DaggerLockscreenShadeTransitionControllerTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, false)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            notificationShadeDepthController = depthController,
+                            keyguardBypassController = keyguardBypassController,
+                            mediaHierarchyManager = mediaHierarchyManager,
+                            notificationLockscreenUserManager = lockScreenUserManager,
+                            notificationStackScrollLayoutController = nsslController,
+                            scrimController = scrimController,
+                            statusBarStateController = statusbarStateController,
+                        )
+                )
+
+        transitionController.addCallback(transitionControllerCallback)
+        transitionController.shadeViewController = shadeViewController
+        transitionController.centralSurfaces = centralSurfaces
+        transitionController.qS = qS
+        transitionController.setStackScroller(nsslController)
+        clearInvocations(centralSurfaces)
+
+        testScope.runCurrent()
     }
 
     @After
@@ -282,7 +223,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
         transitionController.goToLockedShade(null)
         verify(statusbarStateController, never()).setState(anyInt())
         verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
-        verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
+        verify(centralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
     }
 
     @Test
@@ -318,7 +259,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
         verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(transitionControllerCallback, never())
             .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
-        verify(qsTransitionController, never()).dragDownAmount = anyFloat()
+        verify(qS, never()).setTransitionToFullShadeProgress(anyBoolean(), anyFloat(), anyFloat())
     }
 
     @Test
@@ -329,7 +270,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
         verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(transitionControllerCallback)
             .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
-        verify(qsTransitionController).dragDownAmount = 10f
+        verify(qS).setTransitionToFullShadeProgress(eq(true), anyFloat(), anyFloat())
         verify(depthController).transitionToFullShadeProgress = anyFloat()
     }
 
@@ -532,8 +473,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
 
         transitionController.dragDownAmount = 10f
 
-        verify(singleShadeOverScroller).expansionDragDownAmount = 10f
-        verifyZeroInteractions(splitShadeOverScroller)
+        verify(nsslController).setOverScrollAmount(0)
+        verify(scrimController, never()).setNotificationsOverScrollAmount(anyInt())
     }
 
     @Test
@@ -542,8 +483,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
 
         transitionController.dragDownAmount = 10f
 
-        verify(splitShadeOverScroller).expansionDragDownAmount = 10f
-        verifyZeroInteractions(singleShadeOverScroller)
+        verify(nsslController).setOverScrollAmount(0)
+        verify(scrimController).setNotificationsOverScrollAmount(0)
     }
 
     @Test
@@ -591,6 +532,32 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
         progress: Float,
         lockScreenNotificationsProgress: Float
     ) {
-        scrimController.setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
+        setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
+    }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val transitionController: LockscreenShadeTransitionController
+
+        val configurationController: FakeConfigurationController
+        val disableFlagsRepository: FakeDisableFlagsRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
index fbb8ebfb3e3b26676a1eea7e301cc2975bdc86a8..20e5c43cba193e615bf891aeecd868d92987927f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -29,9 +29,9 @@ import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.mockito.mock
 import org.junit.Before
 import org.junit.Test
@@ -52,7 +52,7 @@ class PulseExpansionHandlerTest : SysuiTestCase() {
     private val collapsedHeight = 300
     private val wakeUpCoordinator: NotificationWakeUpCoordinator = mock()
     private val bypassController: KeyguardBypassController = mock()
-    private val headsUpManager: HeadsUpManagerPhone = mock()
+    private val headsUpManager: HeadsUpManager = mock()
     private val roundnessManager: NotificationRoundnessManager = mock()
     private val configurationController: ConfigurationController = mock()
     private val statusBarStateController: StatusBarStateController = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index d86f8bbbeb15a7ba9a40efb2effc498116963c24..235ac5c2e9cc33ca065d4dbb789926e9e0463a84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -8,15 +8,15 @@ import androidx.test.filters.SmallTest
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.HeadsUpUtil
-import com.android.systemui.res.R
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.test.TestScope
@@ -37,7 +37,7 @@ import org.mockito.junit.MockitoJUnit
 @RunWithLooper
 class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
     @Mock lateinit var notificationListContainer: NotificationListContainer
-    @Mock lateinit var headsUpManager: HeadsUpManagerPhone
+    @Mock lateinit var headsUpManager: HeadsUpManager
     @Mock lateinit var jankMonitor: InteractionJankMonitor
     @Mock lateinit var onFinishAnimationCallback: Runnable
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 257cc5b1b85cf810ed2e86ddfa8aee1e0aebdd9f..4f1581cced912b8ea97964926abb32584316564e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -43,8 +43,8 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
@@ -87,7 +87,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
 
     private val notifPipeline: NotifPipeline = mock()
     private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
-    private val headsUpManager: HeadsUpManager = mock()
+    private val headsUpManager: HeadsUpManagerPhone = mock()
     private val headsUpViewBinder: HeadsUpViewBinder = mock()
     private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
     private val remoteInputManager: NotificationRemoteInputManager = mock()
@@ -435,7 +435,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
 
     private fun addHUN(entry: NotificationEntry) {
         huns.add(entry)
-        whenever(headsUpManager.topEntry).thenReturn(entry)
+        whenever(headsUpManager.getTopEntry()).thenReturn(entry)
         onHeadsUpChangedListener.onHeadsUpStateChanged(entry, true)
         notifLifetimeExtender.cancelLifetimeExtension(entry)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index fbd61f4fe3bdbcc225bc3a91afd65ecaa2e79a9b..546abd4ec79a4b29f36e4a84cb0fb87d660580b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -23,7 +23,6 @@ import android.provider.Settings
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.advanceTimeBy
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -40,10 +39,10 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.mockito.any
@@ -247,7 +246,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
             unseenFilter.onCleanup()
 
             // THEN: The SeenNotificationProvider has been updated to reflect the suppression
-            assertThat(seenNotificationsProvider.hasFilteredOutSeenNotifications).isTrue()
+            assertThat(notificationListInteractor.hasFilteredOutSeenNotifications.value).isTrue()
         }
     }
 
@@ -598,7 +597,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
             FakeSettings().apply {
                 putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
             }
-        val seenNotificationsProvider = SeenNotificationsProviderImpl()
+        val notificationListInteractor = NotificationListInteractor(NotificationListRepository())
         val keyguardCoordinator =
             KeyguardCoordinator(
                 testDispatcher,
@@ -611,7 +610,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
                 testScope.backgroundScope,
                 sectionHeaderVisibilityProvider,
                 fakeSettings,
-                seenNotificationsProvider,
+                notificationListInteractor,
                 statusBarStateController,
             )
         keyguardCoordinator.attach(notifPipeline)
@@ -619,7 +618,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
             KeyguardCoordinatorTestScope(
                     keyguardCoordinator,
                     testScope,
-                    seenNotificationsProvider,
+                    notificationListInteractor,
                     fakeSettings,
                 )
                 .testBlock()
@@ -629,7 +628,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
     private inner class KeyguardCoordinatorTestScope(
         private val keyguardCoordinator: KeyguardCoordinator,
         private val scope: TestScope,
-        val seenNotificationsProvider: SeenNotificationsProvider,
+        val notificationListInteractor: NotificationListInteractor,
         private val fakeSettings: FakeSettings,
     ) : CoroutineScope by scope {
         val testScheduler: TestCoroutineScheduler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..99c3b194a662cceab387f154db4a652f6ffac287
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+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.power.data.repository.FakePowerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
+
+    @Mock private lateinit var dozeParams: DozeParameters
+
+    private lateinit var testComponent: TestComponent
+    private val underTest
+        get() = testComponent.underTest
+    private val deviceProvisioningRepository
+        get() = testComponent.deviceProvisioningRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val keyguardTransitionRepository
+        get() = testComponent.keyguardTransitionRepository
+    private val powerRepository
+        get() = testComponent.powerRepository
+    private val scope
+        get() = testComponent.scope
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        testComponent =
+            DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FACE_AUTH_REFACTOR, value = false)
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            dozeParameters = dozeParams,
+                        ),
+                )
+
+        keyguardRepository.setKeyguardShowing(true)
+        keyguardRepository.setKeyguardOccluded(false)
+        deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+        powerRepository.updateWakefulness(
+            rawState = WakefulnessState.AWAKE,
+            lastWakeReason = WakeSleepReason.OTHER,
+            lastSleepReason = WakeSleepReason.OTHER,
+        )
+    }
+
+    @Test
+    fun animationsEnabled_isFalse_whenFrpIsActive() =
+        scope.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenNotAsleep() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenKeyguardIsShowing() =
+        scope.runTest {
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            runCurrent()
+
+            assertThat(animationsEnabled).isTrue()
+
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            assertThat(animationsEnabled).isFalse()
+
+            keyguardRepository.setKeyguardShowing(false)
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                BiometricsDomainLayerModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
+
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val powerRepository: FakePowerRepository
+        val scope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d1518f7e0d0891431b297c343464e17fb62cf887
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+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.power.data.repository.FakePowerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
+
+    @Mock lateinit var dozeParams: DozeParameters
+
+    private lateinit var testComponent: TestComponent
+    private val underTest: NotificationIconContainerStatusBarViewModel
+        get() = testComponent.underTest
+    private val deviceProvisioningRepository
+        get() = testComponent.deviceProvisioningRepository
+    private val keyguardTransitionRepository
+        get() = testComponent.keyguardTransitionRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val powerRepository
+        get() = testComponent.powerRepository
+    private val scope
+        get() = testComponent.scope
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        testComponent =
+            DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FACE_AUTH_REFACTOR, value = false)
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            dozeParameters = dozeParams,
+                        ),
+                )
+
+        keyguardRepository.setKeyguardShowing(false)
+        deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+        powerRepository.updateWakefulness(
+            rawState = WakefulnessState.AWAKE,
+            lastWakeReason = WakeSleepReason.OTHER,
+            lastSleepReason = WakeSleepReason.OTHER,
+        )
+    }
+
+    @Test
+    fun animationsEnabled_isFalse_whenFrpIsActive() =
+        scope.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenNotAsleep() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
+        scope.runTest {
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setKeyguardShowing(true)
+            runCurrent()
+
+            assertThat(animationsEnabled).isFalse()
+
+            keyguardRepository.setKeyguardShowing(false)
+            runCurrent()
+
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                BiometricsDomainLayerModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: NotificationIconContainerStatusBarViewModel
+
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val powerRepository: FakePowerRepository
+        val scope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 9f2afdf1b168be4c5fd22f1e766eee80bc4d69f2..1ab36b805ca6db584440f3f2baf61f078c08a92f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -33,7 +33,6 @@ import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -89,8 +88,8 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -152,7 +151,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
     @Mock private AssistantFeedbackController mAssistantFeedbackController;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private StatusBarStateController mStatusBarStateController;
-    @Mock private HeadsUpManagerPhone mHeadsUpManagerPhone;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private ActivityStarter mActivityStarter;
 
     @Mock private UserManager mUserManager;
@@ -171,7 +170,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
                 mTestScope.getBackgroundScope(),
                 new WindowRootViewVisibilityRepository(mBarService, mExecutor),
                 new FakeKeyguardRepository(),
-                mHeadsUpManagerPhone,
+                mHeadsUpManager,
                 PowerInteractorFactory.create().getPowerInteractor());
 
         mGutsManager = new NotificationGutsManager(
@@ -198,7 +197,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
                 mStatusBarStateController,
                 mDeviceProvisionedController,
                 mMetricsLogger,
-                mHeadsUpManagerPhone,
+                mHeadsUpManager,
                 mActivityStarter);
         mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
                 mOnSettingsClickListener);
@@ -239,7 +238,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
                 anyInt(),
                 anyBoolean(),
                 any(Runnable.class));
-        verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), true);
+        verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), true);
 
         assertEquals(View.VISIBLE, guts.getVisibility());
         mGutsManager.closeAndSaveGuts(false, false, true, 0, 0, false);
@@ -247,7 +246,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
         verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
         verify(row, times(1)).setGutsView(any());
         mTestableLooper.processAllMessages();
-        verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), false);
+        verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index ac680e6c902ef55d53e74563ef9e9618b4e2108b..cb731082b89b7408ee42849db58da8f779f61d9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -61,6 +61,7 @@ import com.android.systemui.flags.Flags;
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -81,14 +82,13 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
-import com.android.systemui.res.R;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.systemui.wmshell.BubblesTestActivity;
 
@@ -123,7 +123,7 @@ public class NotificationTestHelper {
     private final GroupMembershipManager mGroupMembershipManager;
     private final GroupExpansionManager mGroupExpansionManager;
     private ExpandableNotificationRow mRow;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotifBindPipeline mBindPipeline;
     private final NotifCollectionListener mBindPipelineEntryListener;
     private final RowContentBindStage mBindStage;
@@ -161,7 +161,7 @@ public class NotificationTestHelper {
         mKeyguardBypassController = mock(KeyguardBypassController.class);
         mGroupMembershipManager = mock(GroupMembershipManager.class);
         mGroupExpansionManager = mock(GroupExpansionManager.class);
-        mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+        mHeadsUpManager = mock(HeadsUpManager.class);
         mIconManager = new IconManager(
                 mock(CommonNotifCollection.class),
                 mock(LauncherApps.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index ffe312be8faeeb142846953b5467bf9f98ddf842..20197e3ed547d5c4f3ca3b4c643c6136f648cf6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifStats;
@@ -88,13 +87,15 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
 import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor;
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
@@ -124,7 +125,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationsController mNotificationsController;
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
     @Mock private TunerService mTunerService;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -170,8 +171,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
     @Captor
     private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
 
-    private final SeenNotificationsProviderImpl mSeenNotificationsProvider =
-            new SeenNotificationsProviderImpl();
+    private final NotificationListInteractor mNotificationListInteractor =
+            new NotificationListInteractor(new NotificationListRepository());
 
     private NotificationStackScrollLayoutController mController;
 
@@ -503,7 +504,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
     @Test
     public void testSetNotifStats_updatesHasFilteredOutSeenNotifications() {
         initController(/* viewIsAttached= */ true);
-        mSeenNotificationsProvider.setHasFilteredOutSeenNotifications(true);
+        mNotificationListInteractor.setHasFilteredOutSeenNotifications(true);
         mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());
         verify(mNotificationStackScrollLayout).setHasFilteredOutSeenNotifications(true);
         verify(mNotificationStackScrollLayout).updateFooter();
@@ -703,7 +704,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
                 mUiEventLogger,
                 mRemoteInputManager,
                 mVisibilityLocationProviderDelegator,
-                mSeenNotificationsProvider,
+                mNotificationListInteractor,
                 mShadeController,
                 mJankMonitor,
                 mStackLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index e254dd085b2ed7c686709489bcf56b4c78d7a8c8..ac11ff29b83a039352315a4341372e99df389097 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -19,36 +19,35 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
+import com.android.SysUITestModule
+import com.android.TestMocksModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.res.R
 import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.domain.UserDomainLayerModule
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -60,29 +59,27 @@ import org.mockito.MockitoAnnotations
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
-    private val utils = SceneTestUtils(this)
-
-    private val testScope = utils.testScope
-
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val shadeRepository = FakeShadeRepository()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-
-    private lateinit var configurationRepository: FakeConfigurationRepository
-    private lateinit var sharedNotificationContainerInteractor:
-        SharedNotificationContainerInteractor
-    private lateinit var underTest: SharedNotificationContainerViewModel
-    private lateinit var keyguardInteractor: KeyguardInteractor
-    private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
-    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
-    private lateinit var shadeInteractor: ShadeInteractor
+
+    private lateinit var testComponent: TestComponent
+
+    private val shadeRepository
+        get() = testComponent.shadeRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val configurationRepository
+        get() = testComponent.configurationRepository
+    private val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
+        get() = testComponent.sharedNotificationContainerInteractor
+    private val underTest: SharedNotificationContainerViewModel
+        get() = testComponent.underTest
+    private val keyguardInteractor: KeyguardInteractor
+        get() = testComponent.keyguardInteractor
+    private val keyguardTransitionRepository
+        get() = testComponent.keyguardTransitionRepository
+    private val testScope
+        get() = testComponent.testScope
 
     @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator
-    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock private lateinit var userInteractor: UserInteractor
     @Mock
     private lateinit var notificationStackScrollLayoutController:
         NotificationStackScrollLayoutController
@@ -94,43 +91,21 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
         whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())
         whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0)
 
-        configurationRepository = FakeConfigurationRepository()
-        KeyguardTransitionInteractorFactory.create(
-                scope = testScope.backgroundScope,
-            )
-            .also {
-                keyguardInteractor = it.keyguardInteractor
-                keyguardTransitionInteractor = it.keyguardTransitionInteractor
-                keyguardTransitionRepository = it.repository
-            }
-        sharedNotificationContainerInteractor =
-            SharedNotificationContainerInteractor(
-                configurationRepository,
-                mContext,
-                ResourcesSplitShadeStateController()
-            )
-        shadeInteractor =
-            ShadeInteractor(
-                testScope.backgroundScope,
-                disableFlagsRepository,
-                sceneContainerFlags,
-                { sceneInteractor },
-                keyguardRepository,
-                userSetupRepository,
-                deviceProvisionedController,
-                userInteractor,
-                sharedNotificationContainerInteractor,
-                shadeRepository,
-            )
-        underTest =
-            SharedNotificationContainerViewModel(
-                sharedNotificationContainerInteractor,
-                keyguardInteractor,
-                keyguardTransitionInteractor,
-                notificationStackSizeCalculator,
-                notificationStackScrollLayoutController,
-                shadeInteractor
-            )
+        testComponent =
+            DaggerSharedNotificationContainerViewModelTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            notificationStackSizeCalculator = notificationStackSizeCalculator,
+                            notificationStackScrollLayoutController =
+                                notificationStackScrollLayoutController,
+                        )
+                )
     }
 
     @Test
@@ -404,4 +379,34 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
             )
         )
     }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: SharedNotificationContainerViewModel
+
+        val configurationRepository: FakeConfigurationRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardInteractor: KeyguardInteractor
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val shadeRepository: FakeShadeRepository
+        val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index a5d34840424011c8f92891c65396ef261e286d2b..e7dad6a2908f611b41c800bd431199fec78afe65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -57,6 +57,7 @@ import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 
@@ -85,7 +86,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
     private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private KeyguardStateController mKeyguardStateController;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
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 e33fa22bfc0c928a33a6898eaf1f79d009d62593..f18af61dd314878e21bf557f429c68854c2bf75c 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
@@ -85,7 +85,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.TestScopeProvider;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.InitController;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -117,6 +116,7 @@ import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.settings.brightness.BrightnessSliderController;
@@ -219,7 +219,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
     @Mock private KeyguardIndicationController mKeyguardIndicationController;
     @Mock private NotificationStackScrollLayout mStackScroller;
     @Mock private NotificationStackScrollLayoutController mStackScrollerController;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private ShadeLogger mShadeLogger;
     @Mock private NotificationPanelView mNotificationPanelView;
@@ -336,6 +336,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
         mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
         // Set default value to avoid IllegalStateException.
         mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+        mFeatureFlags.setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);
         // For the Shade to respond to Back gesture, we must enable the event routing
         mFeatureFlags.set(Flags.WM_SHADE_ALLOW_BACK_GESTURE, true);
         // For the Shade to animate during the Back gesture, we must enable the animation flag.
@@ -343,6 +344,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
         mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);
         // Turn AOD on and toggle feature flag for jank fixes
         mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false);
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
 
         IThermalService thermalService = mock(IThermalService.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index ff6f40d539fc723714c2b46dbd1151532189dcdd..593c587c0f514d9b5d0bde6b7927d28830b1e937 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -72,7 +73,7 @@ public class DozeServiceHostTest extends SysuiTestCase {
 
     private DozeServiceHost mDozeServiceHost;
 
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index ec6286b66ed2c9fe61826d916d2066aaf6f5fd51..d84bb728a856954b8f8a136792d723d9a959affb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Assert;
@@ -72,7 +73,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
     private ExpandableNotificationRow mRow;
     private NotificationEntry mEntry;
     private HeadsUpStatusBarView mHeadsUpStatusBarView;
-    private HeadsUpManagerPhone mHeadsUpManager;
+    private HeadsUpManager mHeadsUpManager;
     private View mOperatorNameView;
     private StatusBarStateController mStatusbarStateController;
     private PhoneStatusBarTransitions mPhoneStatusBarTransitions;
@@ -93,7 +94,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
         mEntry = mRow.getEntry();
         mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
                 mock(TextView.class));
-        mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+        mHeadsUpManager = mock(HeadsUpManager.class);
         mOperatorNameView = new View(mContext);
         mStatusbarStateController = mock(StatusBarStateController.class);
         mPhoneStatusBarTransitions = mock(PhoneStatusBarTransitions.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 1bc522d72213f89aeb533d81a116bb0dd59b6731..cda2a74609bd5b0b4acc5856b71f18df00a0f255 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -32,8 +32,8 @@ import android.testing.TestableLooper;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.collection.provider.VisualSta
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 
 import org.junit.After;
@@ -71,7 +72,6 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
     @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
     @Mock private UiEventLogger mUiEventLogger;
-    private boolean mLivesPastNormalTime;
 
     private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
         TestableHeadsUpManagerPhone(
@@ -149,7 +149,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testSnooze() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hmp.showNotification(entry);
@@ -160,7 +160,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testSwipedOutNotification() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hmp.showNotification(entry);
@@ -176,7 +176,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testCanRemoveImmediately_swipedOut() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hmp.showNotification(entry);
@@ -189,7 +189,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
     @Ignore("b/141538055")
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry earlierEntry = createEntry(/* id = */ 0);
         final NotificationEntry laterEntry = createEntry(/* id = */ 1);
         laterEntry.setRow(mRow);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index bac857910329d9dfc2c362b94c9d8021fc0b52db..b36d09df59292d726de50773eed061d3d2ff0602 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
+
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -33,7 +36,6 @@ import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
 
 import android.service.trust.TrustAgentService;
 import android.testing.AndroidTestingRunner;
@@ -175,6 +177,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
         mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);
         mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, true);
         mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false);
 
         when(mNotificationShadeWindowController.getWindowRootView())
                 .thenReturn(mNotificationShadeWindowView);
@@ -760,6 +763,30 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
         verify(mPrimaryBouncerInteractor, never()).hide();
     }
 
+    @Test
+    public void handleDispatchTouchEvent_alternateBouncerViewFlagEnabled() {
+        mStatusBarKeyguardViewManager.addCallback(mCallback);
+
+        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, true);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // THEN the touch is not acted upon
+        verify(mCallback, never()).onTouch(any());
+    }
+
+    @Test
+    public void onInterceptTouch_alternateBouncerViewFlagEnabled() {
+        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, true);
+        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);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 8013e5eef44b43dc03c42dd89bfd595f0251e895..beac995c893b493797ef8850ec41a6ad5620ad37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -92,6 +92,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -218,7 +219,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
                 mScreenOffAnimationController,
                 mStatusBarStateController).getPowerInteractor();
 
-        HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
+        HeadsUpManager headsUpManager = mock(HeadsUpManager.class);
         NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =
                 new NotificationLaunchAnimatorControllerProvider(
                         new NotificationExpansionRepository(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 233f407813b2b8bf2cb044229572e13422a395d3..ee4f2089c05c66abb9032c033b01b869ebb2bace 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -15,6 +15,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -59,6 +60,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
@@ -106,7 +108,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
                 mContext,
                 shadeViewController,
                 mock(QuickSettingsController.class),
-                mock(HeadsUpManagerPhone.class),
+                mock(HeadsUpManager.class),
                 notificationShadeWindowView,
                 mock(ActivityStarter.class),
                 stackScrollLayoutController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index dbaa29bb36886d53395f072e04010c25647dea11..d06a6e26b4ce24521f9bcd05326bef2c8fa0665d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -20,7 +20,6 @@ import android.net.ConnectivityManager
 import android.net.wifi.WifiManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.demomode.DemoMode
 import com.android.systemui.demomode.DemoModeController
@@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiRepositorySwitcherTest : SysuiTestCase() {
     private lateinit var underTest: WifiRepositorySwitcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt
index 206ac1d37074b2e1c42dec6d528d673caee1cfb2..ce00250467f6cd196f5ca54dc77ad58928c250b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -28,7 +27,6 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DisabledWifiRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index c2e75aa85fcbf1a9c551f0090016ce4759043150..cf20ba87e8c2f310a33d0288e6258ba864777b54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -35,7 +35,6 @@ import android.net.wifi.WifiManager.UNKNOWN_SSID
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.log.table.TableLogBuffer
@@ -73,7 +72,6 @@ import org.mockito.MockitoAnnotations
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiRepositoryImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
index 1db80651bf9b8e061afdcada3c113a6aa049d1c9..7fbbfc77300ea28d3f79bd73e617d127829dfbd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
 import android.net.wifi.WifiManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
@@ -43,7 +42,6 @@ import org.junit.runner.RunWith
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiInteractorImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 49a2648a7caca2d93792065cd47d0c8a1455b640..2d1a27f1b133418c809c3fff1dacd5a989f554d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.coroutines.collectLastValue
@@ -53,7 +52,6 @@ import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiViewModelTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 64ebcd9e3abf16a4e0b44b322e8bfc5e9a9fe22c..4f3f56423eb04dd3a30fcbf05253da6aeee66faa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -41,10 +41,13 @@ import android.app.PendingIntent;
 import android.app.Person;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Region;
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
@@ -73,7 +76,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
     private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
     @Mock private AccessibilityManagerWrapper mAccessibilityMgr;
 
-    private final class TestableHeadsUpManager extends HeadsUpManager {
+    private final class TestableHeadsUpManager extends BaseHeadsUpManager {
         TestableHeadsUpManager(Context context,
                 HeadsUpManagerLogger logger,
                 Handler handler,
@@ -85,9 +88,78 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
             mStickyDisplayTime = TEST_STICKY_AUTO_DISMISS_TIME;
         }
+
+        // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
+        @Override
+        public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void addSwipedOutNotification(@NonNull String key) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void extendHeadsUp() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Nullable
+        @Override
+        public Region getTouchableRegion() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isHeadsUpGoingAway() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void onExpandingFinished() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
+                boolean animate) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setRemoteInputActive(@NonNull NotificationEntry entry,
+                boolean remoteInputActive) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setTrackingHeadsUp(boolean tracking) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean shouldSwallowClick(@NonNull String key) {
+            throw new UnsupportedOperationException();
+        }
     }
 
-    private HeadsUpManager createHeadsUpManager() {
+    private BaseHeadsUpManager createHeadsUpManager() {
         return new TestableHeadsUpManager(mContext, mLogger, mTestHandler, mAccessibilityMgr,
                 mUiEventLoggerFake);
     }
@@ -165,9 +237,10 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testHunRemovedLogging() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = mock(HeadsUpManager.HeadsUpEntry.class);
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
+                BaseHeadsUpManager.HeadsUpEntry.class);
         headsUpEntry.mEntry = notifEntry;
 
         hum.onAlertEntryRemoved(headsUpEntry);
@@ -177,35 +250,37 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);
 
         // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
-        headsUpEntry.wasUnpinned = false;
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
+        headsUpEntry.mWasUnpinned = false;
 
         assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry));
     }
 
     @Test
     public void testShouldHeadsUpBecomePinned_wasUnpinned_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);
 
         // Add notifEntry to ANM mAlertEntries map and make it unpinned
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
-        headsUpEntry.wasUnpinned = true;
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
+        headsUpEntry.mWasUnpinned = true;
 
         assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry));
     }
 
     @Test
     public void testShouldHeadsUpBecomePinned_noFSI_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         assertFalse(hum.shouldHeadsUpBecomePinned(entry));
@@ -214,7 +289,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -228,7 +303,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShowNotification_autoDismissesWithDefaultTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -242,7 +317,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShowNotification_stickyForSomeTime_autoDismissesWithStickyTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -256,7 +331,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShowNotification_sticky_neverAutoDismisses() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -278,7 +353,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(true);
 
@@ -292,7 +367,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testShowNotification_stickyForSomeTime_autoDismissesWithAccessibilityTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
         useAccessibilityTimeout(true);
 
@@ -306,7 +381,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testRemoveNotification_beforeMinimumDisplayTime() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -329,7 +404,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testRemoveNotification_afterMinimumDisplayTime() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -366,7 +441,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testRemoveNotification_releaseImmediately() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hum.showNotification(entry);
@@ -382,14 +457,15 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testIsSticky_rowPinnedAndExpanded_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
         when(mRow.isPinned()).thenReturn(true);
         notifEntry.setRow(mRow);
 
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
         headsUpEntry.setExpanded(true);
 
         assertTrue(hum.isSticky(notifEntry.getKey()));
@@ -397,20 +473,21 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testIsSticky_remoteInputActive_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
-        headsUpEntry.remoteInputActive = true;
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
+        headsUpEntry.mRemoteInputActive = true;
 
         assertTrue(hum.isSticky(notifEntry.getKey()));
     }
 
     @Test
     public void testIsSticky_hasFullScreenIntent_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
@@ -421,7 +498,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testIsSticky_stickyForSomeTime_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
 
         hum.showNotification(entry);
@@ -432,21 +509,22 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testIsSticky_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
         headsUpEntry.setExpanded(false);
-        headsUpEntry.remoteInputActive = false;
+        headsUpEntry.mRemoteInputActive = false;
 
         assertFalse(hum.isSticky(notifEntry.getKey()));
     }
 
     @Test
     public void testCompareTo_withNullEntries() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
 
         hum.showNotification(alertEntry);
@@ -458,7 +536,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testCompareTo_withNonAlertEntries() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
         final NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag(
                 "nae1").build();
@@ -474,9 +552,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
-        final HeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
         ongoingCall.setEntry(new NotificationEntryBuilder()
                 .setSbn(createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
@@ -484,9 +562,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
                                 .setOngoing(true)))
                 .build());
 
-        final HeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
         activeRemoteInput.setEntry(createEntry(/* id = */ 1));
-        activeRemoteInput.remoteInputActive = true;
+        activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
         assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0);
@@ -494,9 +572,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
-        final HeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry();
         final Person person = new Person.Builder().setName("person").build();
         final PendingIntent intent = mock(PendingIntent.class);
         incomingCall.setEntry(new NotificationEntryBuilder()
@@ -506,9 +584,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
                                         .forIncomingCall(person, intent, intent))))
                 .build());
 
-        final HeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
         activeRemoteInput.setEntry(createEntry(/* id = */ 1));
-        activeRemoteInput.remoteInputActive = true;
+        activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
         assertThat(activeRemoteInput.compareTo(incomingCall)).isGreaterThan(0);
@@ -516,10 +594,10 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
 
     @Test
     public void testPinEntry_logsPeek() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
         // Needs full screen intent in order to be pinned
-        final HeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry();
         entryToPin.setEntry(createFullScreenIntentEntry(/* id = */ 0));
 
         // Note: the standard way to show a notification would be calling showNotification rather
@@ -530,13 +608,13 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
         hum.onAlertEntryAdded(entryToPin);
 
         assertEquals(1, mUiEventLoggerFake.numLogs());
-        assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
+        assertEquals(BaseHeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
                 mUiEventLoggerFake.eventId(0));
     }
 
     @Test
     public void testSetUserActionMayIndirectlyRemove() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..12694ae998c1240333c7c49b16d2327d7b9a2b52
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.policy.data.repository
+
+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.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProvisioningRepositoryImplTest : SysuiTestCase() {
+
+    @Mock lateinit var deviceProvisionedController: DeviceProvisionedController
+
+    lateinit var underTest: DeviceProvisioningRepositoryImpl
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            DeviceProvisioningRepositoryImpl(
+                deviceProvisionedController,
+            )
+    }
+
+    @Test
+    fun isDeviceProvisioned_reflectsCurrentControllerState() = runTest {
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned)
+        assertThat(deviceProvisioned).isTrue()
+    }
+
+    @Test
+    fun isDeviceProvisioned_updatesWhenControllerStateChanges_toTrue() = runTest {
+        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned)
+        runCurrent()
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onDeviceProvisionedChanged()
+        assertThat(deviceProvisioned).isTrue()
+    }
+
+    @Test
+    fun isDeviceProvisioned_updatesWhenControllerStateChanges_toFalse() = runTest {
+        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned)
+        runCurrent()
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onDeviceProvisionedChanged()
+        assertThat(deviceProvisioned).isFalse()
+    }
+
+    @Test
+    fun isFrpActive_reflectsCurrentControllerState() = runTest {
+        whenever(deviceProvisionedController.isFrpActive).thenReturn(true)
+        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive)
+        assertThat(frpActive).isTrue()
+    }
+
+    @Test
+    fun isFrpActive_updatesWhenControllerStateChanges_toTrue() = runTest {
+        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive)
+        runCurrent()
+        whenever(deviceProvisionedController.isFrpActive).thenReturn(true)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onFrpActiveChanged()
+        assertThat(frpActive).isTrue()
+    }
+
+    @Test
+    fun isFrpActive_updatesWhenControllerStateChanges_toFalse() = runTest {
+        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive)
+        runCurrent()
+        whenever(deviceProvisionedController.isFrpActive).thenReturn(false)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onFrpActiveChanged()
+        assertThat(frpActive).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index af941d03f191a5219b06bc3cfadf6d044ef53898..c56266dde7523c792ac7a78cd98f6e7b132988a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -155,6 +155,9 @@ class UserInteractorTest : SysuiTestCase() {
 
     @Test
     fun createUserInteractor_nonProcessUser_startsSecondaryService() {
+        val userId = Process.myUserHandle().identifier + 1
+        whenever(manager.aliveUsers).thenReturn(listOf(createUserInfo(userId, "abc")))
+
         createUserInteractor(false /* startAsProcessUser */)
         verify(spyContext).startServiceAsUser(any(), any())
     }
@@ -655,9 +658,10 @@ class UserInteractorTest : SysuiTestCase() {
 
     @Test
     fun userSwitchedBroadcast() {
-        createUserInteractor()
         testScope.runTest {
             val userInfos = createUserInfos(count = 2, includeGuest = false)
+            whenever(manager.aliveUsers).thenReturn(userInfos)
+            createUserInteractor()
             userRepository.setUserInfos(userInfos)
             userRepository.setSelectedUserInfo(userInfos[0])
             userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -727,6 +731,26 @@ class UserInteractorTest : SysuiTestCase() {
         }
     }
 
+    @Test
+    fun localeChanged_refreshUsers() {
+        createUserInteractor()
+        testScope.runTest {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            runCurrent()
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                spyContext,
+                Intent(Intent.ACTION_LOCALE_CHANGED)
+            )
+            runCurrent()
+
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+        }
+    }
+
     @Test
     fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() {
         createUserInteractor()
@@ -985,6 +1009,13 @@ class UserInteractorTest : SysuiTestCase() {
         }
     }
 
+    @Test
+    fun initWithNoAliveUsers() {
+        whenever(manager.aliveUsers).thenReturn(listOf())
+        createUserInteractor()
+        verify(spyContext, never()).startServiceAsUser(any(), any())
+    }
+
     private fun assertUsers(
         models: List<UserModel>?,
         count: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 6932f5ed4b30e6cb2340512478114ce26b81c569..c236b12d723f73c638466d41cba15060c458ad26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -28,6 +28,7 @@ import com.android.systemui.GuestResetOrExitSessionReceiver
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Text
+import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -346,6 +347,24 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
             job.cancel()
         }
 
+    @Test
+    fun isFinishRequested_finishesWhenUserButtonIsClicked() =
+        testScope.runTest {
+            setUsers(count = 2)
+            val isFinishRequested = mutableListOf<Boolean>()
+            val job =
+                launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
+
+            val userViewModels = collectLastValue(underTest.users)
+            assertThat(isFinishRequested.last()).isFalse()
+
+            userViewModels.invoke()?.firstOrNull()?.onClicked?.invoke()
+
+            assertThat(isFinishRequested.last()).isTrue()
+
+            job.cancel()
+        }
+
     @Test
     fun guestSelected_nameIsExitGuest() =
         testScope.runTest {
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 409ba4801d0d20bed541c916cd6dbccb9ad228db..c8327029026d5e251ac633fe406276dda332bb06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -86,20 +86,36 @@ import androidx.test.filters.SmallTest;
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.keyguard.KeyguardSecurityModel;
 import com.android.launcher3.icons.BubbleIconFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.scene.FakeWindowRootViewComponent;
 import com.android.systemui.scene.SceneTestUtils;
+import com.android.systemui.scene.data.repository.SceneContainerRepository;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
+import com.android.systemui.scene.shared.logger.SceneLogger;
 import com.android.systemui.settings.FakeDisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -139,6 +155,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.user.domain.interactor.UserInteractor;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.WindowManagerShellWrapper;
@@ -329,6 +346,8 @@ public class BubblesTest extends SysuiTestCase {
     private UserHandle mUser0;
 
     private FakeBubbleProperties mBubbleProperties;
+    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor;
+    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;
 
     @Before
     public void setUp() throws Exception {
@@ -350,21 +369,94 @@ public class BubblesTest extends SysuiTestCase {
         when(mNotificationShadeWindowView.getViewTreeObserver())
                 .thenReturn(mock(ViewTreeObserver.class));
 
-        mShadeInteractor = new ShadeInteractor(
+
+        FakeDeviceProvisioningRepository deviceProvisioningRepository =
+                new FakeDeviceProvisioningRepository();
+        deviceProvisioningRepository.setDeviceProvisioned(true);
+        FakeKeyguardRepository keyguardRepository = new FakeKeyguardRepository();
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        FakeShadeRepository shadeRepository = new FakeShadeRepository();
+        FakePowerRepository powerRepository = new FakePowerRepository();
+        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
+
+        PowerInteractor powerInteractor = new PowerInteractor(
+                powerRepository,
+                new FalsingCollectorFake(),
+                mock(ScreenOffAnimationController.class),
+                mStatusBarStateController);
+
+        SceneInteractor sceneInteractor = new SceneInteractor(
                 mTestScope.getBackgroundScope(),
-                new FakeDisableFlagsRepository(),
-                new FakeSceneContainerFlags(),
-                mUtils::sceneInteractor,
-                new FakeKeyguardRepository(),
-                new FakeUserSetupRepository(),
-                mock(DeviceProvisionedController.class),
-                mock(UserInteractor.class),
-                new SharedNotificationContainerInteractor(
-                        new FakeConfigurationRepository(),
-                        mContext,
-                        new ResourcesSplitShadeStateController()),
-                new FakeShadeRepository()
-        );
+                new SceneContainerRepository(
+                        mTestScope.getBackgroundScope(),
+                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+                powerRepository,
+                mock(SceneLogger.class));
+
+        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
+                keyguardRepository,
+                new FakeCommandQueue(),
+                powerInteractor,
+                featureFlags,
+                sceneContainerFlags,
+                new FakeDeviceEntryRepository(),
+                new FakeKeyguardBouncerRepository(),
+                configurationRepository,
+                shadeRepository,
+                () -> sceneInteractor);
+
+        FakeKeyguardTransitionRepository keyguardTransitionRepository =
+                new FakeKeyguardTransitionRepository();
+
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                new KeyguardTransitionInteractor(
+                        mTestScope.getBackgroundScope(),
+                        keyguardTransitionRepository,
+                        () -> keyguardInteractor,
+                        () -> mFromLockscreenTransitionInteractor,
+                        () -> mFromPrimaryBouncerTransitionInteractor);
+
+        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                shadeRepository,
+                powerInteractor);
+
+        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mock(KeyguardSecurityModel.class),
+                powerInteractor);
+
+        ResourcesSplitShadeStateController splitShadeStateController =
+                new ResourcesSplitShadeStateController();
+
+        mShadeInteractor =
+                new ShadeInteractor(
+                        mTestScope.getBackgroundScope(),
+                        deviceProvisioningRepository,
+                        new FakeDisableFlagsRepository(),
+                        mDozeParameters,
+                        sceneContainerFlags,
+                        () -> sceneInteractor,
+                        keyguardRepository,
+                        keyguardTransitionInteractor,
+                        powerInteractor,
+                        new FakeUserSetupRepository(),
+                        mock(UserInteractor.class),
+                        new SharedNotificationContainerInteractor(
+                                configurationRepository,
+                                mContext,
+                                splitShadeStateController),
+                        new FakeShadeRepository()
+                );
 
         mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
                 mContext,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
index 0e594964bb3057ecb761c79fc995a310c391e461..813197b171adfe13c6e5e39cee2ab920f3ef3e23 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
@@ -15,21 +15,27 @@
  */
 package com.android.systemui
 
+import com.android.systemui.classifier.FakeClassifierModule
 import com.android.systemui.data.FakeSystemUiDataLayerModule
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.log.FakeUiEventLoggerModule
 import com.android.systemui.scene.FakeSceneModule
 import com.android.systemui.settings.FakeSettingsModule
+import com.android.systemui.statusbar.policy.FakeConfigurationControllerModule
+import com.android.systemui.statusbar.policy.FakeSplitShadeStateControllerModule
 import com.android.systemui.util.concurrency.FakeExecutorModule
 import dagger.Module
 
 @Module(
     includes =
         [
+            FakeClassifierModule::class,
+            FakeConfigurationControllerModule::class,
             FakeExecutorModule::class,
             FakeFeatureFlagsClassicModule::class,
-            FakeSettingsModule::class,
             FakeSceneModule::class,
+            FakeSettingsModule::class,
+            FakeSplitShadeStateControllerModule::class,
             FakeSystemUiDataLayerModule::class,
             FakeUiEventLoggerModule::class,
         ]
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..23bad39a262e16580f9997dbaa84d9c039213c58
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.classifier
+
+import dagger.Module
+
+@Module(includes = [FakeFalsingCollectorModule::class, FakeFalsingManagerModule::class])
+object FakeClassifierModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..92acc9465bb0e1aebc5fd1f418fb96ee4647a8b4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.classifier
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface FakeFalsingCollectorModule {
+    @Binds @FalsingCollectorActual fun bindFake(fake: FalsingCollectorFake): FalsingCollector
+    @Binds fun bindFakeLegacy(fake: FalsingCollectorFake): FalsingCollector
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..554fc75ec1db36a354821052835d79b4c0b2b0d1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.classifier
+
+import com.android.systemui.plugins.FalsingManager
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface FakeFalsingManagerModule {
+    @Binds fun bindFake(fake: FalsingManagerFake): FalsingManager
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
index d47e88fc9385922fb75b6a45da210a7c963a34c6..5038285aef0058f7be6f63c3b4e1e721f50b70f8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -21,15 +21,19 @@ import static com.google.common.truth.Truth.assertWithMessage;
 import android.net.Uri;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.FalsingManager;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.inject.Inject;
+
 /**
  * Simple Fake for testing where {@link FalsingManager} is required.
  */
+@SysUISingleton
 public class FalsingManagerFake implements FalsingManager {
     private boolean mIsFalseTouch;
     private boolean mIsSimpleTap;
@@ -46,6 +50,10 @@ public class FalsingManagerFake implements FalsingManager {
     private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>();
     private final List<FalsingTapListener> mTapListeners = new ArrayList<>();
 
+    @Inject
+    public FalsingManagerFake() {
+    }
+
     @Override
     public void onSuccessfulUnlock() {
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
index f866932309bb4d3058c0d2faed297c7c37422799..29fb52aabd398121312d01e0fc5f4d01bd720566 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
@@ -17,6 +17,7 @@ package com.android.systemui.data
 
 import com.android.systemui.bouncer.data.repository.FakeBouncerDataLayerModule
 import com.android.systemui.common.ui.data.FakeCommonDataLayerModule
+import com.android.systemui.deviceentry.data.FakeDeviceEntryDataLayerModule
 import com.android.systemui.keyguard.data.FakeKeyguardDataLayerModule
 import com.android.systemui.power.data.FakePowerDataLayerModule
 import com.android.systemui.shade.data.repository.FakeShadeDataLayerModule
@@ -28,8 +29,9 @@ import dagger.Module
 @Module(
     includes =
         [
-            FakeCommonDataLayerModule::class,
             FakeBouncerDataLayerModule::class,
+            FakeCommonDataLayerModule::class,
+            FakeDeviceEntryDataLayerModule::class,
             FakeKeyguardDataLayerModule::class,
             FakePowerDataLayerModule::class,
             FakeShadeDataLayerModule::class,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ef02bdd9c35cf12cbc758444747f03a3fb8c4546
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.deviceentry.data
+
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
index 5e60a09e006bcabb4ce9f35dadd326134d1482c3..26d95c0a0ea38d3f487b4bc431babccaac55b2a8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
@@ -1,11 +1,16 @@
 package com.android.systemui.deviceentry.data.repository
 
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 
 /** Fake implementation of [DeviceEntryRepository] */
-class FakeDeviceEntryRepository : DeviceEntryRepository {
+@SysUISingleton
+class FakeDeviceEntryRepository @Inject constructor() : DeviceEntryRepository {
 
     private var isInsecureLockscreenEnabled = true
     private var isBypassEnabled = false
@@ -33,3 +38,8 @@ class FakeDeviceEntryRepository : DeviceEntryRepository {
         this.isBypassEnabled = isBypassEnabled
     }
 }
+
+@Module
+interface FakeDeviceEntryRepositoryModule {
+    @Binds fun bindFake(fake: FakeDeviceEntryRepository): DeviceEntryRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
index 1bec82b0875b9dd2bff8ff7bb23627cde1669e96..822edfc7f6cdca8cfd7d99c5707dd643a4814d32 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.data
 
 import com.android.systemui.statusbar.disableflags.data.FakeStatusBarDisableFlagsDataLayerModule
 import com.android.systemui.statusbar.pipeline.data.FakeStatusBarPipelineDataLayerModule
+import com.android.systemui.statusbar.policy.data.FakeStatusBarPolicyDataLayerModule
 import dagger.Module
 
 @Module(
@@ -24,6 +25,7 @@ import dagger.Module
         [
             FakeStatusBarDisableFlagsDataLayerModule::class,
             FakeStatusBarPipelineDataLayerModule::class,
+            FakeStatusBarPolicyDataLayerModule::class,
         ]
 )
 object FakeStatusBarDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
index 16a32686956204674a6faa5b2a92c09e450e183e..23477d86807c444c417a1f711c7a2a6491fe456c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -1,9 +1,14 @@
 package com.android.systemui.statusbar.policy
 
 import android.content.res.Configuration
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
 
 /** Fake implementation of [ConfigurationController] for tests. */
-class FakeConfigurationController : ConfigurationController {
+@SysUISingleton
+class FakeConfigurationController @Inject constructor() : ConfigurationController {
 
     private var listeners = mutableListOf<ConfigurationController.ConfigurationListener>()
 
@@ -33,3 +38,8 @@ class FakeConfigurationController : ConfigurationController {
 
     override fun isLayoutRtl(): Boolean = false
 }
+
+@Module
+interface FakeConfigurationControllerModule {
+    @Binds fun bindFake(fake: FakeConfigurationController): ConfigurationController
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..14bab84e62b25a3d317273d75f74118ae98dd2c0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.statusbar.policy
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface FakeSplitShadeStateControllerModule {
+    @Binds fun bindFake(fake: ResourcesSplitShadeStateController): SplitShadeStateController
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
similarity index 58%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
index 3fff136db03a5fae487a57f11ebf353911cc4d10..5aece1bbbd3134c1ef33bcd2747954cb88fbec4f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
@@ -13,19 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.systemui.statusbar.policy.data
 
-package com.android.systemui;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepositoryModule
+import dagger.Module
 
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Mark as tests for Robolectric pilot projects. The filter can better help grouping test results
- * that runs on CI
- */
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface RoboPilotTest {
-}
+@Module(includes = [FakeDeviceProvisioningRepositoryModule::class])
+object FakeStatusBarPolicyDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..300229954044bd0db06a353c6023bed0c0816d24
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.statusbar.policy.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+@SysUISingleton
+class FakeDeviceProvisioningRepository @Inject constructor() : DeviceProvisioningRepository {
+    private val _isDeviceProvisioned = MutableStateFlow(false)
+    override val isDeviceProvisioned: Flow<Boolean> = _isDeviceProvisioned
+    private val _isFactoryResetProtectionActive = MutableStateFlow(false)
+    override val isFactoryResetProtectionActive: Flow<Boolean> = _isFactoryResetProtectionActive
+    fun setDeviceProvisioned(isProvisioned: Boolean) {
+        _isDeviceProvisioned.value = isProvisioned
+    }
+    fun setFactoryResetProtectionActive(isActive: Boolean) {
+        _isFactoryResetProtectionActive.value = isActive
+    }
+}
+
+@Module
+interface FakeDeviceProvisioningRepositoryModule {
+    @Binds fun bindFake(fake: FakeDeviceProvisioningRepository): DeviceProvisioningRepository
+}
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index 155dc1a6829553df57ae91911ff6340b2bf921ca..18f783146c7292e41b0ebe82e7791442e4fe3559 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -49,7 +49,7 @@ android_test {
         "androidx.test.core",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     resource_dirs: ["test/res"],
     certificate: "platform",
diff --git a/packages/overlays/tests/Android.bp b/packages/overlays/tests/Android.bp
index b781602399a3b3d8012fe67706dd6e3129fca152..0244c0fe05332d469c62471911dc8889aa0a72ee 100644
--- a/packages/overlays/tests/Android.bp
+++ b/packages/overlays/tests/Android.bp
@@ -34,7 +34,7 @@ android_test {
         "androidx.test.rules",
         "androidx.test.espresso.core",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     dxflags: ["--multi-dex"],
 }
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index d43a219e620583da8f17145398d821d2e2799649..eb23f2f9b435d8757f9310e4286dcd74dfef2ef6 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -19,19 +19,4 @@ java_library_static {
     defaults: ["platform_service_defaults"],
     srcs: [":services.autofill-sources"],
     libs: ["services.core"],
-    static_libs: ["autofill_flags_java_lib"],
-}
-
-aconfig_declarations {
-    name: "autofill_flags",
-    package: "android.service.autofill",
-    srcs: [
-        "bugfixes.aconfig",
-        "features.aconfig",
-    ],
-}
-
-java_aconfig_library {
-    name: "autofill_flags_java_lib",
-    aconfig_declarations: "autofill_flags",
 }
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ef237546378eff817ce608ee4d3f6fc1f44492e8..123b65c039ba0790be20f3f25734b9ac7227e46d 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -5,4 +5,11 @@ flag {
   namespace: "autofill"
   description: "Test flag "
   bug: "297380045"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "relayout"
+  namespace: "autofill"
+  description: "Mitigation for relayout issue"
+  bug: "294330426"
+}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 9bab261bb0f4637494cb237eada367ef3f892b3c..93dca2f4f19248315a575537a3b858f1e05beae0 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -359,8 +359,10 @@ public final class PinnerService extends SystemService {
                     @Override
                     public void onChange(boolean selfChange, Uri uri) {
                         if (userSetupCompleteUri.equals(uri)) {
-                            sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(),
-                                    true /* force */);
+                            if (mConfiguredToPinHome) {
+                                sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(),
+                                        true /* force */);
+                            }
                         }
                     }
                 }, UserHandle.USER_ALL);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8cc2665b356280affd6aa245fa00eac694108d03..962f38f10b5de1968c95be9caba9c705ef32ec69 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -214,6 +214,9 @@ class StorageManagerService extends IStorageManager.Stub
     // external storage service.
     public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
 
+     /** Extended timeout for the system server watchdog. */
+    private static final int SLOW_OPERATION_WATCHDOG_TIMEOUT_MS = 60 * 1000;
+
     @GuardedBy("mLock")
     private final Set<Integer> mFuseMountedUser = new ArraySet<>();
 
@@ -1230,6 +1233,8 @@ class StorageManagerService extends IStorageManager.Stub
     private void onUserStopped(int userId) {
         Slog.d(TAG, "onUserStopped " + userId);
 
+        Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");
         try {
             mVold.onUserStopped(userId);
             mStoraged.onUserStopped(userId);
@@ -1312,6 +1317,8 @@ class StorageManagerService extends IStorageManager.Stub
                 unlockedUsers.add(userId);
             }
         }
+        Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");
         for (Integer userId : unlockedUsers) {
             try {
                 mVold.onUserStopped(userId);
@@ -3600,6 +3607,8 @@ class StorageManagerService extends IStorageManager.Stub
 
         @Override
         public ParcelFileDescriptor open() throws AppFuseMountException {
+            Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#open might be slow");
             try {
                 final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);
                 mMounted = true;
@@ -3612,6 +3621,8 @@ class StorageManagerService extends IStorageManager.Stub
         @Override
         public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
                 throws AppFuseMountException {
+            Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#openFile might be slow");
             try {
                 return new ParcelFileDescriptor(
                         mVold.openAppFuseFile(uid, mountId, fileId, flags));
@@ -3622,6 +3633,8 @@ class StorageManagerService extends IStorageManager.Stub
 
         @Override
         public void close() throws Exception {
+            Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#close might be slow");
             if (mMounted) {
                 mVold.unmountAppFuse(uid, mountId);
                 mMounted = false;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index b05b397a45de7d0472d0e9e0b294b17fa0a94c2c..55aa7164a67bbd2610f4c68032bf205fb4a7f1ed 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -643,6 +643,16 @@ public class Watchdog implements Dumpable {
         }
     }
 
+    /**
+     * Sets a one-off timeout for the next run of the watchdog for the monitor thread.
+     *
+     * <p>Simiar to {@link setOneOffTimeoutForCurrentThread} but used for monitors added through
+     * {@link #addMonitor}
+     */
+    public void setOneOffTimeoutForMonitors(int oneOffTimeoutMillis, String reason) {
+        mMonitorChecker.setOneOffTimeoutLocked(oneOffTimeoutMillis, reason);
+    }
+
     /**
      * Pauses Watchdog action for the currently running thread. Useful before executing long running
      * operations that could falsely trigger the watchdog. Each call to this will require a matching
diff --git a/services/core/java/com/android/server/am/AnrTimer.java b/services/core/java/com/android/server/am/AnrTimer.java
index 378a386022117717860a95b71589d3d9c9e32efb..9ba49ce35dad2996a9471c77082863f368e248c0 100644
--- a/services/core/java/com/android/server/am/AnrTimer.java
+++ b/services/core/java/com/android/server/am/AnrTimer.java
@@ -107,6 +107,14 @@ class AnrTimer<V> {
      */
     private static final boolean ENABLE_TRACING = false;
 
+    /**
+     * Return true if the feature is enabled.  By default, the value is take from the Flags class
+     * but it can be changed for local testing.
+     */
+    private static boolean anrTimerServiceEnabled() {
+        return Flags.anrTimerServiceEnabled();
+    }
+
     /**
      * The status of an ANR timer.  TIMER_INVALID status is returned when an error is detected.
      */
@@ -327,18 +335,33 @@ class AnrTimer<V> {
      */
     @VisibleForTesting
     static class Injector {
+        private final Handler mReferenceHandler;
+
+        Injector(@NonNull Handler handler) {
+            mReferenceHandler = handler;
+        }
+
         /**
-         * Return a handler for the given Callback.
+         * Return a handler for the given Callback, based on the reference handler. The handler
+         * might be mocked, in which case it does not have a valid Looper.  In this case, use the
+         * main Looper.
          */
+        @NonNull
         Handler getHandler(@NonNull Handler.Callback callback) {
-            return null;
+            Looper looper = mReferenceHandler.getLooper();
+            if (looper == null) looper = Looper.getMainLooper();
+            return new Handler(looper, callback);
         };
 
-        /**
-         * Return a CpuTracker.
-         */
+        /** Return a CpuTracker. */
+        @NonNull
         CpuTracker getTracker() {
-            return null;
+            return new CpuTracker();
+        }
+
+        /** Return true if the feature is enabled. */
+        boolean getFeatureEnabled() {
+            return anrTimerServiceEnabled();
         }
     }
 
@@ -375,12 +398,6 @@ class AnrTimer<V> {
         /** The interface to fetch process statistics that might extend an ANR timeout. */
         private final CpuTracker mCpu;
 
-        /** Create a HandlerTimerService based on the input handler. */
-        HandlerTimerService(@NonNull Handler handler) {
-            mHandler = new Handler(handler.getLooper(), this::expires);
-            mCpu = new CpuTracker();
-        }
-
         /** Create a HandlerTimerService that directly uses the supplied handler and tracker. */
         @VisibleForTesting
         HandlerTimerService(@NonNull Injector injector) {
@@ -490,39 +507,57 @@ class AnrTimer<V> {
      */
     private final boolean mLenientCancel = true;
 
+    /**
+     * The top-level switch for the feature enabled or disabled.
+     */
+    private final FeatureSwitch mFeature;
+
     /**
      * The common constructor.  A null injector results in a normal, production timer.
      */
     @VisibleForTesting
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend,
-            @Nullable Injector injector) {
+            @NonNull Injector injector) {
         mHandler = handler;
         mWhat = what;
         mLabel = label;
         mExtend = extend;
-        if (injector == null) {
-            mTimerService = new HandlerTimerService(handler);
+        boolean enabled = injector.getFeatureEnabled();
+        if (!enabled) {
+            mFeature = new FeatureDisabled();
+            mTimerService = null;
         } else {
+            mFeature = new FeatureEnabled();
             mTimerService = new HandlerTimerService(injector);
+
+            synchronized (sAnrTimerList) {
+                sAnrTimerList.add(new WeakReference(this));
+            }
         }
-        synchronized (sAnrTimerList) {
-            sAnrTimerList.add(new WeakReference(this));
-        }
-        Log.i(TAG, formatSimple("created %s label: \"%s\"", mTimerService.toString(), label));
+        Log.i(TAG, formatSimple("created %s label: \"%s\"", mTimerService, label));
     }
 
     /**
      * Create one timer instance for production.  The client can ask for extensible timeouts.
      */
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
-        this(handler, what, label, extend, null);
+        this(handler, what, label, extend, new Injector(handler));
     }
 
     /**
      * Create one timer instance for production.  There are no extensible timeouts.
      */
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
-        this(handler, what, label, false, null);
+        this(handler, what, label, false);
+    }
+
+    /**
+     * Return true if the service is enabled on this instance.  Clients should use this method to
+     * decide if the feature is enabled, and not read the flags directly.  This method should be
+     * deleted if and when the feature is enabled permanently.
+     */
+    boolean serviceEnabled() {
+        return mFeature.enabled();
     }
 
     /**
@@ -613,93 +648,186 @@ class AnrTimer<V> {
         Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));
     }
 
-   /**
-     * Start a timer.
+    /**
+     * The FeatureSwitch class provides a quick switch between feature-enabled behavior and
+     * feature-disabled behavior.
      */
-    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
-        final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, this);
-        synchronized (mLock) {
-            Timer old = mTimerMap.get(arg);
-            if (old != null) {
-                // There is an existing timer.  This is a protocol error in the client.  Record
-                // the error and then clean up by canceling running timers and discarding expired
-                // timers.
-                restartedLocked(old.status, arg);
-                if (old.status == TIMER_EXPIRED) {
-                    discard(arg);
+    private abstract class FeatureSwitch {
+        abstract boolean start(@NonNull V arg, int pid, int uid, long timeoutMs);
+        abstract boolean cancel(@NonNull V arg);
+        abstract boolean accept(@NonNull V arg);
+        abstract boolean discard(@NonNull V arg);
+        abstract boolean enabled();
+    }
+
+    /**
+     * The FeatureDisabled class bypasses almost all AnrTimer logic.  It is used when the AnrTimer
+     * service is disabled via Flags.anrTimerServiceEnabled.
+     */
+    private class FeatureDisabled extends FeatureSwitch {
+        /** Start a timer by sending a message to the client's handler. */
+        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+            final Message msg = mHandler.obtainMessage(mWhat, arg);
+            mHandler.sendMessageDelayed(msg, timeoutMs);
+            return true;
+        }
+
+        /** Cancel a timer by removing the message from the client's handler. */
+        boolean cancel(@NonNull V arg) {
+            mHandler.removeMessages(mWhat, arg);
+            return true;
+        }
+
+        /** accept() is a no-op when the feature is disabled. */
+        boolean accept(@NonNull V arg) {
+            return true;
+        }
+
+        /** discard() is a no-op when the feature is disabled. */
+        boolean discard(@NonNull V arg) {
+            return true;
+        }
+
+        /** The feature is not enabled. */
+        boolean enabled() {
+            return false;
+        }
+    }
+
+    /**
+     * The FeatureEnabled class enables the AnrTimer logic.  It is used when the AnrTimer service
+     * is enabled via Flags.anrTimerServiceEnabled.
+     */
+    private class FeatureEnabled extends FeatureSwitch {
+
+        /**
+         * Start a timer.
+         */
+        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+            final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, AnrTimer.this);
+            synchronized (mLock) {
+                Timer old = mTimerMap.get(arg);
+                if (old != null) {
+                    // There is an existing timer.  This is a protocol error in the client.
+                    // Record the error and then clean up by canceling running timers and
+                    // discarding expired timers.
+                    restartedLocked(old.status, arg);
+                    if (old.status == TIMER_EXPIRED) {
+                        discard(arg);
+                    } else {
+                        cancel(arg);
+                    }
+                }
+                if (mTimerService.start(timer)) {
+                    timer.status = TIMER_RUNNING;
+                    mTimerMap.put(arg, timer);
+                    mTotalStarted++;
+                    mMaxStarted = Math.max(mMaxStarted, mTimerMap.size());
+                    if (DEBUG) report(timer, "start");
+                    return true;
                 } else {
-                    cancel(arg);
+                    Log.e(TAG, "AnrTimer.start failed");
+                    return false;
                 }
             }
-            if (mTimerService.start(timer)) {
-                timer.status = TIMER_RUNNING;
-                mTimerMap.put(arg, timer);
-                mTotalStarted++;
-                mMaxStarted = Math.max(mMaxStarted, mTimerMap.size());
-                if (DEBUG) report(timer, "start");
+        }
+
+        /**
+         * Cancel a timer.  Return false if the timer was not found.
+         */
+        boolean cancel(@NonNull V arg) {
+            synchronized (mLock) {
+                Timer timer = removeLocked(arg);
+                if (timer == null) {
+                    if (!mLenientCancel) notFoundLocked("cancel", arg);
+                    return false;
+                }
+                mTimerService.cancel(timer);
+                // There may be an expiration message in flight.  Cancel it.
+                mHandler.removeMessages(mWhat, arg);
+                if (DEBUG) report(timer, "cancel");
+                timer.release();
                 return true;
-            } else {
-                Log.e(TAG, "AnrTimer.start failed");
-                return false;
             }
         }
+
+        /**
+         * Accept a timer in the framework-level handler.  The timeout has been accepted and the
+         * timeout handler is executing.  Return false if the timer was not found.
+         */
+        boolean accept(@NonNull V arg) {
+            synchronized (mLock) {
+                Timer timer = removeLocked(arg);
+                if (timer == null) {
+                    notFoundLocked("accept", arg);
+                    return false;
+                }
+                mTimerService.accept(timer);
+                traceEnd(timer);
+                if (DEBUG) report(timer, "accept");
+                timer.release();
+                return true;
+            }
+        }
+
+        /**
+         * Discard a timer in the framework-level handler.  For whatever reason, the timer is no
+         * longer interesting.  No statistics are collected.  Return false if the time was not
+         * found.
+         */
+        boolean discard(@NonNull V arg) {
+            synchronized (mLock) {
+                Timer timer = removeLocked(arg);
+                if (timer == null) {
+                    notFoundLocked("discard", arg);
+                    return false;
+                }
+                mTimerService.discard(timer);
+                traceEnd(timer);
+                if (DEBUG) report(timer, "discard");
+                timer.release();
+                return true;
+            }
+        }
+
+        /** The feature is enabled. */
+        boolean enabled() {
+            return true;
+        }
     }
 
     /**
-     * Cancel a timer.  Return false if the timer was not found.
+     * Start a timer associated with arg.  If a timer already exists with the same arg, then that
+     * timer is canceled and a new timer is created.  This returns false if the timer cannot be
+     * created.
+     */
+    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+        return mFeature.start(arg, pid, uid, timeoutMs);
+    }
+
+    /**
+     * Cancel a running timer and remove it from any list.  This returns true if the timer was
+     * found and false otherwise.  It is not an error to cancel a non-existent timer.  It is also
+     * not an error to cancel an expired timer.
      */
     boolean cancel(@NonNull V arg) {
-        synchronized (mLock) {
-            Timer timer = removeLocked(arg);
-            if (timer == null) {
-                if (!mLenientCancel) notFoundLocked("cancel", arg);
-                return false;
-            }
-            mTimerService.cancel(timer);
-            // There may be an expiration message in flight.  Cancel it.
-            mHandler.removeMessages(mWhat, arg);
-            if (DEBUG) report(timer, "cancel");
-            timer.release();
-            return true;
-        }
+        return mFeature.cancel(arg);
     }
 
     /**
-     * Accept a timer in the framework-level handler.  The timeout has been accepted and the
-     * timeout handler is executing.  Return false if the timer was not found.
+     * Accept an expired timer.  This returns false if the timer was not found or if the timer was
+     * not expired.
      */
     boolean accept(@NonNull V arg) {
-        synchronized (mLock) {
-            Timer timer = removeLocked(arg);
-            if (timer == null) {
-                notFoundLocked("accept", arg);
-                return false;
-            }
-            mTimerService.accept(timer);
-            traceEnd(timer);
-            if (DEBUG) report(timer, "accept");
-            timer.release();
-            return true;
-        }
+        return mFeature.accept(arg);
     }
 
     /**
-     * Discard a timer in the framework-level handler.  For whatever reason, the timer is no
-     * longer interesting.  No statistics are collected.  Return false if the time was not found.
+     * Discard an expired timer.  This returns false if the timer was not found or if the timer was
+     * not expired.
      */
     boolean discard(@NonNull V arg) {
-        synchronized (mLock) {
-            Timer timer = removeLocked(arg);
-            if (timer == null) {
-                notFoundLocked("discard", arg);
-                return false;
-            }
-            mTimerService.discard(timer);
-            traceEnd(timer);
-            if (DEBUG) report(timer, "discard");
-            timer.release();
-            return true;
-        }
+        return mFeature.discard(arg);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 907069de8c976c70fd122d9be202f952dd3aab7a..147f8d1a1e3271a91f0e064ca3a13b7531f7eeca 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -580,7 +580,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
                             batteryStatsInternal);
             curDuration += curStart - lastUidBatteryUsageStartTs;
             try {
-                statsCommit.close();
+                if (statsCommit != null) {
+                    statsCommit.close();
+                } else {
+                    Slog.w(TAG, "Stat was null");
+                }
             } catch (IOException e) {
                 Slog.w(TAG, "Failed to close a stat");
             }
@@ -660,7 +664,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
             }
         }
         try {
-            stats.close();
+            if (stats != null) {
+                stats.close();
+            } else {
+                Slog.w(TAG, "Stat was null");
+            }
         } catch (IOException e) {
             Slog.w(TAG, "Failed to close a stat");
         }
@@ -684,7 +692,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
         final BatteryUsageStats stats = statsList.get(0);
         for (int i = 1; i < statsList.size(); i++) {
             try {
-                statsList.get(i).close();
+                if (statsList.get(i) != null) {
+                    statsList.get(i).close();
+                } else {
+                    Slog.w(TAG, "Stat was null");
+                }
             } catch (IOException e) {
                 Slog.w(TAG, "Failed to close a stat in BatteryUsageStats List");
             }
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 5d31d1545b8da43d1ecdd481333591bf4c993709..e07c2bcaaaed3be439bdd2c5ccd1940c26412855 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -106,6 +106,14 @@ class BroadcastProcessQueue {
     private boolean mTimeoutScheduled;
 
     /**
+     * Snapshotted value of {@link ProcessRecord#getCpuDelayTime()}, typically
+     * used when deciding if we should extend the soft ANR timeout.
+     *
+     * Required when Flags.anrTimerServiceEnabled is false.
+     */
+    long lastCpuDelayTime;
+
+     /**
      * Snapshotted value of {@link ProcessStateRecord#getCurProcState()} before
      * dispatching the current broadcast to the receiver in this process.
      */
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index eb219a8819c6ce70a3d6632bd04819a9d6c236ff..a428907073680b5a2cf65b2b0aa590488149f88c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -258,6 +258,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     private static final int MSG_PROCESS_FREEZABLE_CHANGED = 6;
     private static final int MSG_UID_STATE_CHANGED = 7;
 
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private static final int MSG_DELIVERY_TIMEOUT_SOFT = 8;
+
     private void enqueueUpdateRunningList() {
         mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
         mLocalHandler.sendEmptyMessage(MSG_UPDATE_RUNNING_LIST);
@@ -271,6 +274,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                 updateRunningList();
                 return true;
             }
+            // Required when Flags.anrTimerServiceEnabled is false.
+            case MSG_DELIVERY_TIMEOUT_SOFT: {
+                synchronized (mService) {
+                    deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
+                    return true;
+                }
+            }
             case MSG_DELIVERY_TIMEOUT: {
                 deliveryTimeout((BroadcastProcessQueue) msg.obj);
                 return true;
@@ -1030,7 +1040,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
             queue.setTimeoutScheduled(true);
             final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT
                     : mBgConstants.TIMEOUT);
-            mAnrTimer.start(queue, softTimeoutMillis);
+            startDeliveryTimeoutLocked(queue, softTimeoutMillis);
         } else {
             queue.setTimeoutScheduled(false);
         }
@@ -1110,7 +1120,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                 // If we were trying to deliver a manifest broadcast, throw the error as we need
                 // to try redelivering the broadcast to this receiver.
                 if (receiver instanceof ResolveInfo) {
-                    mAnrTimer.cancel(queue);
+                    cancelDeliveryTimeoutLocked(queue);
                     throw new BroadcastDeliveryFailedException(e);
                 }
                 finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
@@ -1159,6 +1169,41 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
         r.resultTo = null;
     }
 
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private void startDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue,
+            int softTimeoutMillis) {
+        if (mAnrTimer.serviceEnabled()) {
+            mAnrTimer.start(queue, softTimeoutMillis);
+        } else {
+            queue.lastCpuDelayTime = queue.app.getCpuDelayTime();
+            mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler,
+                    MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis);
+        }
+    }
+
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private void cancelDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) {
+        mAnrTimer.cancel(queue);
+        if (!mAnrTimer.serviceEnabled()) {
+            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
+        }
+    }
+
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
+            int softTimeoutMillis) {
+        if (queue.app != null) {
+            // Instead of immediately triggering an ANR, extend the timeout by
+            // the amount of time the process was runnable-but-waiting; we're
+            // only willing to do this once before triggering an hard ANR
+            final long cpuDelayTime = queue.app.getCpuDelayTime() - queue.lastCpuDelayTime;
+            final long hardTimeoutMillis = MathUtils.constrain(cpuDelayTime, 0, softTimeoutMillis);
+            mAnrTimer.start(queue, hardTimeoutMillis);
+        } else {
+            deliveryTimeoutLocked(queue);
+        }
+    }
+
     private void deliveryTimeout(@NonNull BroadcastProcessQueue queue) {
         synchronized (mService) {
             deliveryTimeoutLocked(queue);
@@ -1292,7 +1337,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                 mAnrTimer.discard(queue);
             }
         } else if (queue.timeoutScheduled()) {
-            mAnrTimer.cancel(queue);
+            cancelDeliveryTimeoutLocked(queue);
         }
 
         // Given that a receiver just finished, check if the "waitingFor" conditions are met.
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 4a0bc4b9ca6c8c84a7d3c2fa09659fc77e1066d4..816043e6554469064eccfa76c34c7ca211dc457e 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -131,12 +131,14 @@ public class SettingsToPropertiesMapper {
         "car_telemetry",
         "codec_fwk",
         "companion",
+        "content_protection",
         "context_hub",
         "core_experiments_team_internal",
         "core_graphics",
         "haptics",
         "hardware_backed_security_mainline",
         "machine_learning",
+        "mainline_sdk",
         "media_audio",
         "media_solutions",
         "nfc",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index b03cc6295b8d5046db2c894535b037c7700af338..26d99d843c7eb6c9ae1ce1df8f0ebd33d67c4e3d 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -6,4 +6,12 @@ flag {
     description: "Utilize new OomAdjuster implementation"
     bug: "298055811"
     is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+     name: "anr_timer_service_enabled"
+     namespace: "system_performance"
+     is_fixed_read_only: true
+     description: "Feature flag for the ANR timer service"
+     bug: "282428924"
+}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 9805fd3d13161409f09533cf193c9a6497d14fe4..333f62a81e94131747b8f008792c4311db614593 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1845,7 +1845,7 @@ public class SyncStorageEngine {
     private void parseListenForTickles(TypedXmlPullParser parser) {
         int userId = 0;
         try {
-            parser.getAttributeInt(null, XML_ATTR_USER);
+            userId = parser.getAttributeInt(null, XML_ATTR_USER);
         } catch (XmlPullParserException e) {
             Slog.e(TAG, "error parsing the user for listen-for-tickles", e);
         }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 9e92c8d7342db16a4009e36f02a93648d81bd833..cfbe0c69b32019e22a81b05343b2a77588e06689 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -60,6 +60,9 @@ import com.android.server.display.config.LuxThrottling;
 import com.android.server.display.config.NitsMap;
 import com.android.server.display.config.NonNegativeFloatToFloatPoint;
 import com.android.server.display.config.Point;
+import com.android.server.display.config.PowerThrottlingConfig;
+import com.android.server.display.config.PowerThrottlingMap;
+import com.android.server.display.config.PowerThrottlingPoint;
 import com.android.server.display.config.PredefinedBrightnessLimitNames;
 import com.android.server.display.config.RefreshRateConfigs;
 import com.android.server.display.config.RefreshRateRange;
@@ -139,6 +142,30 @@ import javax.xml.datatype.DatatypeConfigurationException;
  *      </screenBrightnessMap>
  *
  *      <screenBrightnessDefault>0.65</screenBrightnessDefault>
+ *      <powerThrottlingConfig>
+ *        <brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>
+ *        <pollingWindowMillis>15</pollingWindowMillis>
+ *          <powerThrottlingMap>
+ *              <powerThrottlingPoint>
+ *                  <thermalStatus>severe</thermalStatus>
+ *                  <powerQuotaMilliWatts>200.6</powerQuotaMilliWatts>
+ *              </powerThrottlingPoint>
+ *              <powerThrottlingPoint>
+ *                  <thermalStatus>critical</thermalStatus>
+ *                  <powerQuotaMilliWatts>300</powerQuotaMilliWatts>
+ *              </powerThrottlingPoint>
+ *          </powerThrottlingMap>
+ *          <powerThrottlingMap id="id_2"> // optional attribute, leave blank for default
+ *             <powerThrottlingPoint>
+ *                 <thermalStatus>moderate</thermalStatus>
+ *                 <powerQuotaMilliWatts>400</powerQuotaMilliWatts>
+ *             </powerThrottlingPoint>
+ *             <powerThrottlingPoint>
+ *                 <thermalStatus>severe</thermalStatus>
+ *                 <powerQuotaMilliWatts>250</powerQuotaMilliWatts>
+ *            </powerThrottlingPoint>
+ *          </powerThrottlingMap>
+ *      </powerThrottlingConfig>
  *
  *      <thermalThrottling>
  *        <brightnessThrottlingMap>
@@ -669,6 +696,8 @@ public class DisplayDeviceConfig {
     private List<String> mQuirks;
     private boolean mIsHighBrightnessModeEnabled = false;
     private HighBrightnessModeData mHbmData;
+    @Nullable
+    private PowerThrottlingConfigData mPowerThrottlingConfigData;
     private DensityMapping mDensityMapping;
     private String mLoadedFrom = null;
     private Spline mSdrToHdrRatioSpline;
@@ -781,6 +810,9 @@ public class DisplayDeviceConfig {
     private final HashMap<String, ThermalBrightnessThrottlingData>
             mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>();
 
+    private final HashMap<String, PowerThrottlingData>
+            mPowerThrottlingDataMapByThrottlingId = new HashMap<>();
+
     private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
             mRefreshRateThrottlingMap = new HashMap<>();
 
@@ -1458,6 +1490,14 @@ public class DisplayDeviceConfig {
         return hbmData;
     }
 
+    /**
+     * @return Power throttling configuration data for the display.
+     */
+    @Nullable
+    public PowerThrottlingConfigData getPowerThrottlingConfigData() {
+        return mPowerThrottlingConfigData;
+    }
+
     @NonNull
     public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() {
         return mLuxThrottlingData;
@@ -1490,6 +1530,14 @@ public class DisplayDeviceConfig {
         return mRefreshRateThrottlingMap.get(key);
     }
 
+    /**
+     * @return power throttling configuration data for this display, for each throttling id.
+     **/
+    public HashMap<String, PowerThrottlingData>
+            getPowerThrottlingDataMapByThrottlingId() {
+        return mPowerThrottlingDataMapByThrottlingId;
+    }
+
     /**
      * @return Auto brightness darkening light debounce
      */
@@ -1702,6 +1750,9 @@ public class DisplayDeviceConfig {
                 + ", mThermalBrightnessThrottlingDataMapByThrottlingId="
                 + mThermalBrightnessThrottlingDataMapByThrottlingId
                 + "\n"
+                + ", mPowerThrottlingDataMapByThrottlingId="
+                + mPowerThrottlingDataMapByThrottlingId
+                + "\n"
                 + "mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
                 + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
@@ -1853,6 +1904,7 @@ public class DisplayDeviceConfig {
                 loadBrightnessConstraintsFromConfigXml();
                 loadBrightnessMap(config);
                 loadThermalThrottlingConfig(config);
+                loadPowerThrottlingConfigData(config);
                 loadHighBrightnessModeData(config);
                 loadLuxThrottling(config);
                 loadQuirks(config);
@@ -2171,6 +2223,59 @@ public class DisplayDeviceConfig {
         }
     }
 
+    private boolean loadPowerThrottlingMaps(PowerThrottlingConfig throttlingConfig) {
+        final List<PowerThrottlingMap> maps = throttlingConfig.getPowerThrottlingMap();
+        if (maps == null || maps.isEmpty()) {
+            Slog.i(TAG, "No power throttling map found");
+            return false;
+        }
+
+        for (PowerThrottlingMap map : maps) {
+            final List<PowerThrottlingPoint> points = map.getPowerThrottlingPoint();
+            // At least 1 point is guaranteed by the display device config schema
+            List<PowerThrottlingData.ThrottlingLevel> throttlingLevels =
+                    new ArrayList<>(points.size());
+
+            boolean badConfig = false;
+            for (PowerThrottlingPoint point : points) {
+                ThermalStatus status = point.getThermalStatus();
+                if (!thermalStatusIsValid(status)) {
+                    badConfig = true;
+                    break;
+                }
+
+                throttlingLevels.add(new PowerThrottlingData.ThrottlingLevel(
+                        convertThermalStatus(status),
+                            point.getPowerQuotaMilliWatts().floatValue()));
+            }
+
+            if (!badConfig) {
+                String id = map.getId() == null ? DEFAULT_ID : map.getId();
+                if (mPowerThrottlingDataMapByThrottlingId.containsKey(id)) {
+                    throw new RuntimeException("Power throttling data with ID " + id
+                            + " already exists");
+                }
+                mPowerThrottlingDataMapByThrottlingId.put(id,
+                        PowerThrottlingData.create(throttlingLevels));
+            }
+        }
+        return true;
+    }
+
+    private void loadPowerThrottlingConfigData(DisplayConfiguration config) {
+        final PowerThrottlingConfig powerThrottlingCfg = config.getPowerThrottlingConfig();
+        if (powerThrottlingCfg == null) {
+            return;
+        }
+        if (!loadPowerThrottlingMaps(powerThrottlingCfg)) {
+            return;
+        }
+        float lowestBrightnessCap = powerThrottlingCfg.getBrightnessLowestCapAllowed().floatValue();
+        int pollingWindowMillis = powerThrottlingCfg.getPollingWindowMillis().intValue();
+        mPowerThrottlingConfigData = new PowerThrottlingConfigData(lowestBrightnessCap,
+                                                                   pollingWindowMillis);
+    }
+
     private void loadRefreshRateSetting(DisplayConfiguration config) {
         final RefreshRateConfigs refreshRateConfigs =
                 (config == null) ? null : config.getRefreshRate();
@@ -3378,6 +3483,148 @@ public class DisplayDeviceConfig {
         }
     }
 
+    /**
+     * Container for Power throttling configuration data.
+     * TODO(b/302814899): extract to separate class.
+     */
+    public static class PowerThrottlingConfigData {
+        /** Lowest brightness cap allowed for this device. */
+        public final float brightnessLowestCapAllowed;
+        /** Time window for polling power in seconds. */
+        public final int pollingWindowMillis;
+        public PowerThrottlingConfigData(float brightnessLowestCapAllowed,
+                int pollingWindowMillis) {
+            this.brightnessLowestCapAllowed = brightnessLowestCapAllowed;
+            this.pollingWindowMillis = pollingWindowMillis;
+        }
+
+        @Override
+        public String toString() {
+            return "PowerThrottlingConfigData{"
+                    + "brightnessLowestCapAllowed: "
+                    + brightnessLowestCapAllowed
+                    + ", pollingWindowMillis: " + pollingWindowMillis
+                    + "} ";
+        }
+    }
+
+    /**
+     * Container for power throttling data.
+     * TODO(b/302814899): extract to separate class and unify with ThermalBrightnessThrottlingData.
+     */
+    public static class PowerThrottlingData {
+        public List<ThrottlingLevel> throttlingLevels;
+
+        /**
+         * thermal status to power quota mapping.
+         */
+        public static class ThrottlingLevel {
+            public @PowerManager.ThermalStatus int thermalStatus;
+            public float powerQuotaMilliWatts;
+
+            public ThrottlingLevel(
+                    @PowerManager.ThermalStatus int thermalStatus, float powerQuotaMilliWatts) {
+                this.thermalStatus = thermalStatus;
+                this.powerQuotaMilliWatts = powerQuotaMilliWatts;
+            }
+
+            @Override
+            public String toString() {
+                return "[" + thermalStatus + "," + powerQuotaMilliWatts + "]";
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (!(obj instanceof ThrottlingLevel)) {
+                    return false;
+                }
+                ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj;
+
+                return otherThrottlingLevel.thermalStatus == this.thermalStatus
+                        && otherThrottlingLevel.powerQuotaMilliWatts == this.powerQuotaMilliWatts;
+            }
+
+            @Override
+            public int hashCode() {
+                int result = 1;
+                result = 31 * result + thermalStatus;
+                result = 31 * result + Float.hashCode(powerQuotaMilliWatts);
+                return result;
+            }
+        }
+
+
+        /**
+         * Creates multiple temperature based throttling levels of power quota.
+         */
+        public static PowerThrottlingData create(
+                List<ThrottlingLevel> throttlingLevels) {
+            if (throttlingLevels == null || throttlingLevels.size() == 0) {
+                Slog.e(TAG, "PowerThrottlingData received null or empty throttling levels");
+                return null;
+            }
+
+            ThrottlingLevel prevLevel = throttlingLevels.get(0);
+            final int numLevels = throttlingLevels.size();
+            for (int i = 1; i < numLevels; i++) {
+                ThrottlingLevel thisLevel = throttlingLevels.get(i);
+
+                if (thisLevel.thermalStatus <= prevLevel.thermalStatus) {
+                    Slog.e(TAG, "powerThrottlingMap must be strictly increasing, ignoring "
+                            + "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= "
+                            + prevLevel.thermalStatus);
+                    return null;
+                }
+
+                if (thisLevel.powerQuotaMilliWatts >= prevLevel.powerQuotaMilliWatts) {
+                    Slog.e(TAG, "powerThrottlingMap must be strictly decreasing, ignoring "
+                            + "configuration. powerQuotaMilliWatts "
+                            + thisLevel.powerQuotaMilliWatts + " >= "
+                            + prevLevel.powerQuotaMilliWatts);
+                    return null;
+                }
+
+                prevLevel = thisLevel;
+            }
+            return new PowerThrottlingData(throttlingLevels);
+        }
+
+        @Override
+        public String toString() {
+            return "PowerThrottlingData{"
+                    + "throttlingLevels:" + throttlingLevels
+                    + "} ";
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+
+            if (!(obj instanceof PowerThrottlingData)) {
+                return false;
+            }
+
+            PowerThrottlingData otherData = (PowerThrottlingData) obj;
+            return throttlingLevels.equals(otherData.throttlingLevels);
+        }
+
+        @Override
+        public int hashCode() {
+            return throttlingLevels.hashCode();
+        }
+
+        @VisibleForTesting
+        PowerThrottlingData(List<ThrottlingLevel> inLevels) {
+            throttlingLevels = new ArrayList<>(inLevels.size());
+            for (ThrottlingLevel level : inLevels) {
+                throttlingLevels.add(new ThrottlingLevel(level.thermalStatus,
+                        level.powerQuotaMilliWatts));
+            }
+        }
+    }
+
     /**
      * Container for brightness throttling data.
      */
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 b6273e1daf82277997ec016cb13e97a553ca2eb5..d5382cb99d2203777cedb39cb83bd327e0bab2d9 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -51,22 +51,10 @@ public class DisplayManagerFlags {
             Flags.FLAG_ENABLE_DISPLAY_OFFLOAD,
             Flags::enableDisplayOffload);
 
-    private final FlagState mDisplayResolutionRangeVotingState = new FlagState(
-            Flags.FLAG_ENABLE_DISPLAY_RESOLUTION_RANGE_VOTING,
-            Flags::enableDisplayResolutionRangeVoting);
-
-    private final FlagState mUserPreferredModeVoteState = new FlagState(
-            Flags.FLAG_ENABLE_USER_PREFERRED_MODE_VOTE,
-            Flags::enableUserPreferredModeVote);
-
     private final FlagState mExternalDisplayLimitModeState = new FlagState(
             Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY,
             Flags::enableModeLimitForExternalDisplay);
 
-    private final FlagState mDisplaysRefreshRatesSynchronizationState = new FlagState(
-            Flags.FLAG_ENABLE_DISPLAYS_REFRESH_RATES_SYNCHRONIZATION,
-            Flags::enableDisplaysRefreshRatesSynchronization);
-
     /** Returns whether connected display management is enabled or not. */
     public boolean isConnectedDisplayManagementEnabled() {
         return mConnectedDisplayManagementFlagState.isEnabled();
@@ -90,7 +78,7 @@ public class DisplayManagerFlags {
 
     /** Returns whether resolution range voting feature is enabled or not. */
     public boolean isDisplayResolutionRangeVotingEnabled() {
-        return mDisplayResolutionRangeVotingState.isEnabled();
+        return isExternalDisplayLimitModeEnabled();
     }
 
     /**
@@ -98,7 +86,7 @@ public class DisplayManagerFlags {
      *      {@link com.android.server.display.mode.DisplayModeDirector}
      */
     public boolean isUserPreferredModeVoteEnabled() {
-        return mUserPreferredModeVoteState.isEnabled();
+        return isExternalDisplayLimitModeEnabled();
     }
 
     /**
@@ -112,7 +100,7 @@ public class DisplayManagerFlags {
      * @return Whether displays refresh rate synchronization is enabled.
      */
     public boolean isDisplaysRefreshRatesSynchronizationEnabled() {
-        return mDisplaysRefreshRatesSynchronizationState.isEnabled();
+        return isExternalDisplayLimitModeEnabled();
     }
 
     /** Returns whether displayoffload is enabled on not */
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index 2ede56dcecd91b2f88d0802b3d537c2d690fb37f..a2c8748a91428ddbb47d3b6035bf4c7f4ad5e397 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -62,10 +62,10 @@ class GestureMonitorSpyWindow {
         mWindowHandle.ownerUid = uid;
         mWindowHandle.scaleFactor = 1.0f;
         mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
-        mWindowHandle.inputConfig =
-                InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY;
+        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SPY;
 
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR);
         t.setPosition(mInputSurface, 0, 0);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6b399def4d7304281ebf4e0e8b03c164112a1aba..2533e029767900e0ac5ecf7bda48b77a273d9e10 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -117,6 +117,7 @@ import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerInternal.LidSwitchCallback;
+import com.android.server.input.debug.FocusEventDebugView;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.policy.WindowManagerPolicy;
 
diff --git a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java b/services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java
similarity index 94%
rename from services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java
rename to services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java
index 67c221f7703766feb84994a6a3550da59b980477..2b21e49a4e034f31e710db4a6a65e5dce170524a 100644
--- a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java
+++ b/services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.input;
+package com.android.server.input.debug;
 
 import android.view.Display;
 import android.view.InputEvent;
@@ -22,6 +22,7 @@ import android.view.InputEventReceiver;
 import android.view.MotionEvent;
 
 import com.android.server.UiThread;
+import com.android.server.input.InputManagerService;
 
 /**
  * Receives input events before they are dispatched and reports them to FocusEventDebugView.
diff --git a/services/core/java/com/android/server/input/FocusEventDebugView.java b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
similarity index 50%
rename from services/core/java/com/android/server/input/FocusEventDebugView.java
rename to services/core/java/com/android/server/input/debug/FocusEventDebugView.java
index 4b8fabde7d35347cb5b267af2b77f548251063e1..6eec0dee91528c5e8176af0c050e1d8f7d1888d2 100644
--- a/services/core/java/com/android/server/input/FocusEventDebugView.java
+++ b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.input;
+package com.android.server.input.debug;
 
 import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 import static android.util.TypedValue.COMPLEX_UNIT_SP;
@@ -24,11 +24,9 @@ import android.animation.LayoutTransition;
 import android.annotation.AnyThread;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.util.DisplayMetrics;
 import android.util.Pair;
@@ -40,7 +38,6 @@ import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.RoundedCorner;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.WindowInsets;
 import android.view.animation.AccelerateInterpolator;
 import android.widget.HorizontalScrollView;
@@ -50,19 +47,17 @@ import android.widget.TextView;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.input.InputManagerService;
 
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Locale;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
 /**
  *  Displays focus events, such as physical keyboard KeyEvents and non-pointer MotionEvents on
  *  the screen.
  */
-class FocusEventDebugView extends RelativeLayout {
+public class FocusEventDebugView extends RelativeLayout {
 
     private static final String TAG = FocusEventDebugView.class.getSimpleName();
 
@@ -112,7 +107,7 @@ class FocusEventDebugView extends RelativeLayout {
         mOuterPadding = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, OUTER_PADDING_DP, mDm);
     }
 
-    FocusEventDebugView(Context c, InputManagerService service) {
+    public FocusEventDebugView(Context c, InputManagerService service) {
         this(c, service, () -> new RotaryInputValueView(c), () -> new RotaryInputGraphView(c));
     }
 
@@ -149,11 +144,13 @@ class FocusEventDebugView extends RelativeLayout {
         return super.dispatchKeyEvent(event);
     }
 
+    /** Determines whether to show the key presses visualization. */
     @AnyThread
     public void updateShowKeyPresses(boolean enabled) {
         post(() -> handleUpdateShowKeyPresses(enabled));
     }
 
+    /** Determines whether to show the rotary input visualization. */
     @AnyThread
     public void updateShowRotaryInput(boolean enabled) {
         post(() -> handleUpdateShowRotaryInput(enabled));
@@ -358,13 +355,6 @@ class FocusEventDebugView extends RelativeLayout {
         return mRotaryInputValueView != null;
     }
 
-    /**
-     * Converts a dimension in scaled pixel units to integer display pixels.
-     */
-    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) {
-        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm);
-    }
-
     private static class PressedKeyView extends TextView {
 
         private static final ColorFilter sInvertColors = new ColorMatrixColorFilter(new float[]{
@@ -473,376 +463,4 @@ class FocusEventDebugView extends RelativeLayout {
             invalidate();
         }
     }
-
-    // TODO(b/286086154): move RotaryInputGraphView and RotaryInputValueView to a subpackage.
-
-    /** Draws the most recent rotary input value and indicates whether the source is active. */
-    @VisibleForTesting
-    static class RotaryInputValueView extends TextView {
-
-        private static final int INACTIVE_TEXT_COLOR = 0xffff00ff;
-        private static final int ACTIVE_TEXT_COLOR = 0xff420f28;
-        private static final int TEXT_SIZE_SP = 8;
-        private static final int SIDE_PADDING_SP = 4;
-        /** Determines how long the active status lasts. */
-        private static final int ACTIVE_STATUS_DURATION = 250 /* milliseconds */;
-        private static final ColorFilter ACTIVE_BACKGROUND_FILTER =
-                new ColorMatrixColorFilter(new float[]{
-                        0, 0, 0, 0, 255, // red
-                        0, 0, 0, 0,   0, // green
-                        0, 0, 0, 0, 255, // blue
-                        0, 0, 0, 0, 200  // alpha
-                });
-
-        private final Runnable mUpdateActivityStatusCallback = () -> updateActivityStatus(false);
-        private final float mScaledVerticalScrollFactor;
-
-        @VisibleForTesting
-        RotaryInputValueView(Context c) {
-            super(c);
-
-            DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
-            mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
-
-            setText(getFormattedValue(0));
-            setTextColor(INACTIVE_TEXT_COLOR);
-            setTextSize(applyDimensionSp(TEXT_SIZE_SP, dm));
-            setPaddingRelative(applyDimensionSp(SIDE_PADDING_SP, dm), 0,
-                    applyDimensionSp(SIDE_PADDING_SP, dm), 0);
-            setTypeface(null, Typeface.BOLD);
-            setBackgroundResource(R.drawable.focus_event_rotary_input_background);
-        }
-
-        void updateValue(float value) {
-            removeCallbacks(mUpdateActivityStatusCallback);
-
-            setText(getFormattedValue(value * mScaledVerticalScrollFactor));
-
-            updateActivityStatus(true);
-            postDelayed(mUpdateActivityStatusCallback, ACTIVE_STATUS_DURATION);
-        }
-
-        @VisibleForTesting
-        void updateActivityStatus(boolean active) {
-            if (active) {
-                setTextColor(ACTIVE_TEXT_COLOR);
-                getBackground().setColorFilter(ACTIVE_BACKGROUND_FILTER);
-            } else {
-                setTextColor(INACTIVE_TEXT_COLOR);
-                getBackground().clearColorFilter();
-            }
-        }
-
-        private static String getFormattedValue(float value) {
-            return String.format("%s%.1f", value < 0 ? "-" : "+", Math.abs(value));
-        }
-    }
-
-    /**
-     * Shows a graph with the rotary input values as a function of time.
-     * The graph gets reset if no action is received for a certain amount of time.
-     */
-    @VisibleForTesting
-    static class RotaryInputGraphView extends View {
-
-        private static final int FRAME_COLOR = 0xbf741b47;
-        private static final int FRAME_WIDTH_SP = 2;
-        private static final int FRAME_BORDER_GAP_SP = 10;
-        private static final int FRAME_TEXT_SIZE_SP = 10;
-        private static final int FRAME_TEXT_OFFSET_SP = 2;
-        private static final int GRAPH_COLOR = 0xffff00ff;
-        private static final int GRAPH_LINE_WIDTH_SP = 1;
-        private static final int GRAPH_POINT_RADIUS_SP = 4;
-        private static final long MAX_SHOWN_TIME_INTERVAL = TimeUnit.SECONDS.toMillis(5);
-        private static final float DEFAULT_FRAME_CENTER_POSITION = 0;
-        private static final int MAX_GRAPH_VALUES_SIZE = 400;
-        /** Maximum time between values so that they are considered part of the same gesture. */
-        private static final long MAX_GESTURE_TIME = TimeUnit.SECONDS.toMillis(1);
-
-        private final DisplayMetrics mDm;
-        /**
-         * Distance in position units (amount scrolled in display pixels) from the center to the
-         * top/bottom frame lines.
-         */
-        private final float mFrameCenterToBorderDistance;
-        private final float mScaledVerticalScrollFactor;
-        private final Locale mDefaultLocale;
-        private final Paint mFramePaint = new Paint();
-        private final Paint mFrameTextPaint = new Paint();
-        private final Paint mGraphLinePaint = new Paint();
-        private final Paint mGraphPointPaint = new Paint();
-
-        private final CyclicBuffer mGraphValues = new CyclicBuffer(MAX_GRAPH_VALUES_SIZE);
-        /** Position at which graph values are placed at the center of the graph. */
-        private float mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
-
-        @VisibleForTesting
-        RotaryInputGraphView(Context c) {
-            super(c);
-
-            mDm = mContext.getResources().getDisplayMetrics();
-            // This makes the center-to-border distance equivalent to the display height, meaning
-            // that the total height of the graph is equivalent to 2x the display height.
-            mFrameCenterToBorderDistance = mDm.heightPixels;
-            mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
-            mDefaultLocale = Locale.getDefault();
-
-            mFramePaint.setColor(FRAME_COLOR);
-            mFramePaint.setStrokeWidth(applyDimensionSp(FRAME_WIDTH_SP, mDm));
-
-            mFrameTextPaint.setColor(GRAPH_COLOR);
-            mFrameTextPaint.setTextSize(applyDimensionSp(FRAME_TEXT_SIZE_SP, mDm));
-
-            mGraphLinePaint.setColor(GRAPH_COLOR);
-            mGraphLinePaint.setStrokeWidth(applyDimensionSp(GRAPH_LINE_WIDTH_SP, mDm));
-            mGraphLinePaint.setStrokeCap(Paint.Cap.ROUND);
-            mGraphLinePaint.setStrokeJoin(Paint.Join.ROUND);
-
-            mGraphPointPaint.setColor(GRAPH_COLOR);
-            mGraphPointPaint.setStrokeWidth(applyDimensionSp(GRAPH_POINT_RADIUS_SP, mDm));
-            mGraphPointPaint.setStrokeCap(Paint.Cap.ROUND);
-            mGraphPointPaint.setStrokeJoin(Paint.Join.ROUND);
-        }
-
-        /**
-         * Reads new scroll axis value and updates the list accordingly. Old positions are
-         * kept at the front (what you would get with getFirst), while the recent positions are
-         * kept at the back (what you would get with getLast). Also updates the frame center
-         * position to handle out-of-bounds cases.
-         */
-        void addValue(float scrollAxisValue, long eventTime) {
-            // Remove values that are too old.
-            while (mGraphValues.getSize() > 0
-                    && (eventTime - mGraphValues.getFirst().mTime) > MAX_SHOWN_TIME_INTERVAL) {
-                mGraphValues.removeFirst();
-            }
-
-            // If there are no recent values, reset the frame center.
-            if (mGraphValues.getSize() == 0) {
-                mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
-            }
-
-            // Handle new value. We multiply the scroll axis value by the scaled scroll factor to
-            // get the amount of pixels to be scrolled. We also compute the accumulated position
-            // by adding the current value to the last one (if not empty).
-            final float displacement = scrollAxisValue * mScaledVerticalScrollFactor;
-            final float prevPos = (mGraphValues.getSize() == 0 ? 0 : mGraphValues.getLast().mPos);
-            final float pos = prevPos + displacement;
-
-            mGraphValues.add(pos, eventTime);
-
-            // The difference between the distance of the most recent position from the center
-            // frame (pos - mFrameCenterPosition) and the maximum allowed distance from the center
-            // frame (mFrameCenterToBorderDistance).
-            final float verticalDiff = Math.abs(pos - mFrameCenterPosition)
-                    - mFrameCenterToBorderDistance;
-            // If needed, translate frame.
-            if (verticalDiff > 0) {
-                final int sign = pos - mFrameCenterPosition < 0 ? -1 : 1;
-                // Here, we update the center frame position by the exact amount needed for us to
-                // stay within the maximum allowed distance from the center frame.
-                mFrameCenterPosition += sign * verticalDiff;
-            }
-
-            // Redraw canvas.
-            invalidate();
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            super.onDraw(canvas);
-
-            // Note: vertical coordinates in Canvas go from top to bottom,
-            // that is bottomY > middleY > topY.
-            final int verticalMargin = applyDimensionSp(FRAME_BORDER_GAP_SP, mDm);
-            final int topY = verticalMargin;
-            final int bottomY = getHeight() - verticalMargin;
-            final int middleY = (topY + bottomY) / 2;
-
-            // Note: horizontal coordinates in Canvas go from left to right,
-            // that is rightX > leftX.
-            final int leftX = 0;
-            final int rightX = getWidth();
-
-            // Draw the frame, which includes 3 lines that show the maximum,
-            // minimum and middle positions of the graph.
-            canvas.drawLine(leftX, topY, rightX, topY, mFramePaint);
-            canvas.drawLine(leftX, middleY, rightX, middleY, mFramePaint);
-            canvas.drawLine(leftX, bottomY, rightX, bottomY, mFramePaint);
-
-            // Draw the position that each frame line corresponds to.
-            final int frameTextOffset = applyDimensionSp(FRAME_TEXT_OFFSET_SP, mDm);
-            canvas.drawText(
-                    String.format(mDefaultLocale, "%.1f",
-                            mFrameCenterPosition + mFrameCenterToBorderDistance),
-                    leftX,
-                    topY - frameTextOffset, mFrameTextPaint
-            );
-            canvas.drawText(
-                    String.format(mDefaultLocale, "%.1f", mFrameCenterPosition),
-                    leftX,
-                    middleY - frameTextOffset, mFrameTextPaint
-            );
-            canvas.drawText(
-                    String.format(mDefaultLocale, "%.1f",
-                            mFrameCenterPosition - mFrameCenterToBorderDistance),
-                    leftX,
-                    bottomY - frameTextOffset, mFrameTextPaint
-            );
-
-            // If there are no graph values to be drawn, stop here.
-            if (mGraphValues.getSize() == 0) {
-                return;
-            }
-
-            // Draw the graph using the times and positions.
-            // We start at the most recent value (which should be drawn at the right) and move
-            // to the older values (which should be drawn to the left of more recent ones). Negative
-            // indices are handled by circuling back to the end of the buffer.
-            final long mostRecentTime = mGraphValues.getLast().mTime;
-            float prevCoordX = 0;
-            float prevCoordY = 0;
-            float prevAge = 0;
-            for (Iterator<GraphValue> iter = mGraphValues.reverseIterator(); iter.hasNext();) {
-                final GraphValue value = iter.next();
-
-                final int age = (int) (mostRecentTime - value.mTime);
-                final float pos = value.mPos;
-
-                // We get the horizontal coordinate in time units from left to right with
-                // (MAX_SHOWN_TIME_INTERVAL - age). Then, we rescale it to match the canvas
-                // units by dividing it by the time-domain length (MAX_SHOWN_TIME_INTERVAL)
-                // and by multiplying it by the canvas length (rightX - leftX). Finally, we
-                // offset the coordinate by adding it to leftX.
-                final float coordX = leftX + ((float) (MAX_SHOWN_TIME_INTERVAL - age)
-                        / MAX_SHOWN_TIME_INTERVAL) * (rightX - leftX);
-
-                // We get the vertical coordinate in position units from middle to top with
-                // (pos - mFrameCenterPosition). Then, we rescale it to match the canvas
-                // units by dividing it by half of the position-domain length
-                // (mFrameCenterToBorderDistance) and by multiplying it by half of the canvas
-                // length (middleY - topY). Finally, we offset the coordinate by subtracting
-                // it from middleY (we can't "add" here because the coordinate grows from top
-                // to bottom).
-                final float coordY = middleY - ((pos - mFrameCenterPosition)
-                        / mFrameCenterToBorderDistance) * (middleY - topY);
-
-                // Draw a point for this value.
-                canvas.drawPoint(coordX, coordY, mGraphPointPaint);
-
-                // If this value is part of the same gesture as the previous one, draw a line
-                // between them. We ignore the first value (with age = 0).
-                if (age != 0 && (age - prevAge) <= MAX_GESTURE_TIME) {
-                    canvas.drawLine(prevCoordX, prevCoordY, coordX, coordY, mGraphLinePaint);
-                }
-
-                prevCoordX = coordX;
-                prevCoordY = coordY;
-                prevAge = age;
-            }
-        }
-
-        @VisibleForTesting
-        float getFrameCenterPosition() {
-            return mFrameCenterPosition;
-        }
-
-        /**
-         * Holds data needed to draw each entry in the graph.
-         */
-        private static class GraphValue {
-            /** Position. */
-            float mPos;
-            /** Time when this value was added. */
-            long mTime;
-
-            GraphValue(float pos, long time) {
-                this.mPos = pos;
-                this.mTime = time;
-            }
-        }
-
-        /**
-         * Holds the graph values as a cyclic buffer. It has a fixed capacity, and it replaces the
-         * old values with new ones to avoid creating new objects.
-         */
-        private static class CyclicBuffer {
-            private final GraphValue[] mValues;
-            private final int mCapacity;
-            private int mSize = 0;
-            private int mLastIndex = 0;
-
-            // The iteration index and counter are here to make it easier to reset them.
-            /** Determines the value currently pointed by the iterator. */
-            private int mIteratorIndex;
-            /** Counts how many values have been iterated through. */
-            private int mIteratorCount;
-
-            /** Used traverse the values in reverse order. */
-            private final Iterator<GraphValue> mReverseIterator = new Iterator<GraphValue>() {
-                @Override
-                public boolean hasNext() {
-                    return mIteratorCount <= mSize;
-                }
-
-                @Override
-                public GraphValue next() {
-                    // Returns the value currently pointed by the iterator and moves the iterator to
-                    // the previous one.
-                    mIteratorCount++;
-                    return mValues[(mIteratorIndex-- + mCapacity) % mCapacity];
-                }
-            };
-
-            CyclicBuffer(int capacity) {
-                mCapacity = capacity;
-                mValues = new GraphValue[capacity];
-            }
-
-            /**
-             * Add new graph value. If there is an existing object, we replace its data with the
-             * new one. With this, we re-use old objects instead of creating new ones.
-             */
-            void add(float pos, long time) {
-                mLastIndex = (mLastIndex + 1) % mCapacity;
-                if (mValues[mLastIndex] == null) {
-                    mValues[mLastIndex] = new GraphValue(pos, time);
-                } else {
-                    final GraphValue oldValue = mValues[mLastIndex];
-                    oldValue.mPos = pos;
-                    oldValue.mTime = time;
-                }
-
-                // If needed, account for new value in the buffer size.
-                if (mSize != mCapacity) {
-                    mSize++;
-                }
-            }
-
-            int getSize() {
-                return mSize;
-            }
-
-            GraphValue getFirst() {
-                final int distanceBetweenLastAndFirst = (mCapacity - mSize) + 1;
-                final int firstIndex = (mLastIndex + distanceBetweenLastAndFirst) % mCapacity;
-                return mValues[firstIndex];
-            }
-
-            GraphValue getLast() {
-                return mValues[mLastIndex];
-            }
-
-            void removeFirst() {
-                mSize--;
-            }
-
-            /** Returns an iterator pointing at the last value. */
-            Iterator<GraphValue> reverseIterator() {
-                mIteratorIndex = mLastIndex;
-                mIteratorCount = 1;
-                return mReverseIterator;
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java b/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java
new file mode 100644
index 0000000000000000000000000000000000000000..95635d925855386c4bd5d9a1f3d596c834e763f4
--- /dev/null
+++ b/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright 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.server.input.debug;
+
+import static android.util.TypedValue.COMPLEX_UNIT_SP;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Shows a graph with the rotary input values as a function of time.
+ * The graph gets reset if no action is received for a certain amount of time.
+ */
+public class RotaryInputGraphView extends View {
+
+    private static final int FRAME_COLOR = 0xbf741b47;
+    private static final int FRAME_WIDTH_SP = 2;
+    private static final int FRAME_BORDER_GAP_SP = 10;
+    private static final int FRAME_TEXT_SIZE_SP = 10;
+    private static final int FRAME_TEXT_OFFSET_SP = 2;
+    private static final int GRAPH_COLOR = 0xffff00ff;
+    private static final int GRAPH_LINE_WIDTH_SP = 1;
+    private static final int GRAPH_POINT_RADIUS_SP = 4;
+    private static final long MAX_SHOWN_TIME_INTERVAL = TimeUnit.SECONDS.toMillis(5);
+    private static final float DEFAULT_FRAME_CENTER_POSITION = 0;
+    private static final int MAX_GRAPH_VALUES_SIZE = 400;
+    /** Maximum time between values so that they are considered part of the same gesture. */
+    private static final long MAX_GESTURE_TIME = TimeUnit.SECONDS.toMillis(1);
+
+    private final DisplayMetrics mDm;
+    /**
+     * Distance in position units (amount scrolled in display pixels) from the center to the
+     * top/bottom frame lines.
+     */
+    private final float mFrameCenterToBorderDistance;
+    private final float mScaledVerticalScrollFactor;
+    private final Locale mDefaultLocale = Locale.getDefault();
+    private final Paint mFramePaint = new Paint();
+    private final Paint mFrameTextPaint = new Paint();
+    private final Paint mGraphLinePaint = new Paint();
+    private final Paint mGraphPointPaint = new Paint();
+
+    private final CyclicBuffer mGraphValues = new CyclicBuffer(MAX_GRAPH_VALUES_SIZE);
+    /** Position at which graph values are placed at the center of the graph. */
+    private float mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
+
+    public RotaryInputGraphView(Context c) {
+        super(c);
+
+        mDm = mContext.getResources().getDisplayMetrics();
+        // This makes the center-to-border distance equivalent to the display height, meaning
+        // that the total height of the graph is equivalent to 2x the display height.
+        mFrameCenterToBorderDistance = mDm.heightPixels;
+        mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
+
+        mFramePaint.setColor(FRAME_COLOR);
+        mFramePaint.setStrokeWidth(applyDimensionSp(FRAME_WIDTH_SP, mDm));
+
+        mFrameTextPaint.setColor(GRAPH_COLOR);
+        mFrameTextPaint.setTextSize(applyDimensionSp(FRAME_TEXT_SIZE_SP, mDm));
+
+        mGraphLinePaint.setColor(GRAPH_COLOR);
+        mGraphLinePaint.setStrokeWidth(applyDimensionSp(GRAPH_LINE_WIDTH_SP, mDm));
+        mGraphLinePaint.setStrokeCap(Paint.Cap.ROUND);
+        mGraphLinePaint.setStrokeJoin(Paint.Join.ROUND);
+
+        mGraphPointPaint.setColor(GRAPH_COLOR);
+        mGraphPointPaint.setStrokeWidth(applyDimensionSp(GRAPH_POINT_RADIUS_SP, mDm));
+        mGraphPointPaint.setStrokeCap(Paint.Cap.ROUND);
+        mGraphPointPaint.setStrokeJoin(Paint.Join.ROUND);
+    }
+
+    /**
+     * Reads new scroll axis value and updates the list accordingly. Old positions are
+     * kept at the front (what you would get with getFirst), while the recent positions are
+     * kept at the back (what you would get with getLast). Also updates the frame center
+     * position to handle out-of-bounds cases.
+     */
+    public void addValue(float scrollAxisValue, long eventTime) {
+        // Remove values that are too old.
+        while (mGraphValues.getSize() > 0
+                && (eventTime - mGraphValues.getFirst().mTime) > MAX_SHOWN_TIME_INTERVAL) {
+            mGraphValues.removeFirst();
+        }
+
+        // If there are no recent values, reset the frame center.
+        if (mGraphValues.getSize() == 0) {
+            mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
+        }
+
+        // Handle new value. We multiply the scroll axis value by the scaled scroll factor to
+        // get the amount of pixels to be scrolled. We also compute the accumulated position
+        // by adding the current value to the last one (if not empty).
+        final float displacement = scrollAxisValue * mScaledVerticalScrollFactor;
+        final float prevPos = (mGraphValues.getSize() == 0 ? 0 : mGraphValues.getLast().mPos);
+        final float pos = prevPos + displacement;
+
+        mGraphValues.add(pos, eventTime);
+
+        // The difference between the distance of the most recent position from the center
+        // frame (pos - mFrameCenterPosition) and the maximum allowed distance from the center
+        // frame (mFrameCenterToBorderDistance).
+        final float verticalDiff = Math.abs(pos - mFrameCenterPosition)
+                - mFrameCenterToBorderDistance;
+        // If needed, translate frame.
+        if (verticalDiff > 0) {
+            final int sign = pos - mFrameCenterPosition < 0 ? -1 : 1;
+            // Here, we update the center frame position by the exact amount needed for us to
+            // stay within the maximum allowed distance from the center frame.
+            mFrameCenterPosition += sign * verticalDiff;
+        }
+
+        // Redraw canvas.
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Note: vertical coordinates in Canvas go from top to bottom,
+        // that is bottomY > middleY > topY.
+        final int verticalMargin = applyDimensionSp(FRAME_BORDER_GAP_SP, mDm);
+        final int topY = verticalMargin;
+        final int bottomY = getHeight() - verticalMargin;
+        final int middleY = (topY + bottomY) / 2;
+
+        // Note: horizontal coordinates in Canvas go from left to right,
+        // that is rightX > leftX.
+        final int leftX = 0;
+        final int rightX = getWidth();
+
+        // Draw the frame, which includes 3 lines that show the maximum,
+        // minimum and middle positions of the graph.
+        canvas.drawLine(leftX, topY, rightX, topY, mFramePaint);
+        canvas.drawLine(leftX, middleY, rightX, middleY, mFramePaint);
+        canvas.drawLine(leftX, bottomY, rightX, bottomY, mFramePaint);
+
+        // Draw the position that each frame line corresponds to.
+        final int frameTextOffset = applyDimensionSp(FRAME_TEXT_OFFSET_SP, mDm);
+        canvas.drawText(
+                String.format(mDefaultLocale, "%.1f",
+                        mFrameCenterPosition + mFrameCenterToBorderDistance),
+                leftX,
+                topY - frameTextOffset, mFrameTextPaint
+        );
+        canvas.drawText(
+                String.format(mDefaultLocale, "%.1f", mFrameCenterPosition),
+                leftX,
+                middleY - frameTextOffset, mFrameTextPaint
+        );
+        canvas.drawText(
+                String.format(mDefaultLocale, "%.1f",
+                        mFrameCenterPosition - mFrameCenterToBorderDistance),
+                leftX,
+                bottomY - frameTextOffset, mFrameTextPaint
+        );
+
+        // If there are no graph values to be drawn, stop here.
+        if (mGraphValues.getSize() == 0) {
+            return;
+        }
+
+        // Draw the graph using the times and positions.
+        // We start at the most recent value (which should be drawn at the right) and move
+        // to the older values (which should be drawn to the left of more recent ones). Negative
+        // indices are handled by circuling back to the end of the buffer.
+        final long mostRecentTime = mGraphValues.getLast().mTime;
+        float prevCoordX = 0;
+        float prevCoordY = 0;
+        float prevAge = 0;
+        for (Iterator<GraphValue> iter = mGraphValues.reverseIterator(); iter.hasNext();) {
+            final GraphValue value = iter.next();
+
+            final int age = (int) (mostRecentTime - value.mTime);
+            final float pos = value.mPos;
+
+            // We get the horizontal coordinate in time units from left to right with
+            // (MAX_SHOWN_TIME_INTERVAL - age). Then, we rescale it to match the canvas
+            // units by dividing it by the time-domain length (MAX_SHOWN_TIME_INTERVAL)
+            // and by multiplying it by the canvas length (rightX - leftX). Finally, we
+            // offset the coordinate by adding it to leftX.
+            final float coordX = leftX + ((float) (MAX_SHOWN_TIME_INTERVAL - age)
+                    / MAX_SHOWN_TIME_INTERVAL) * (rightX - leftX);
+
+            // We get the vertical coordinate in position units from middle to top with
+            // (pos - mFrameCenterPosition). Then, we rescale it to match the canvas
+            // units by dividing it by half of the position-domain length
+            // (mFrameCenterToBorderDistance) and by multiplying it by half of the canvas
+            // length (middleY - topY). Finally, we offset the coordinate by subtracting
+            // it from middleY (we can't "add" here because the coordinate grows from top
+            // to bottom).
+            final float coordY = middleY - ((pos - mFrameCenterPosition)
+                    / mFrameCenterToBorderDistance) * (middleY - topY);
+
+            // Draw a point for this value.
+            canvas.drawPoint(coordX, coordY, mGraphPointPaint);
+
+            // If this value is part of the same gesture as the previous one, draw a line
+            // between them. We ignore the first value (with age = 0).
+            if (age != 0 && (age - prevAge) <= MAX_GESTURE_TIME) {
+                canvas.drawLine(prevCoordX, prevCoordY, coordX, coordY, mGraphLinePaint);
+            }
+
+            prevCoordX = coordX;
+            prevCoordY = coordY;
+            prevAge = age;
+        }
+    }
+
+    public float getFrameCenterPosition() {
+        return mFrameCenterPosition;
+    }
+
+    /**
+     * Converts a dimension in scaled pixel units to integer display pixels.
+     */
+    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) {
+        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm);
+    }
+
+    /**
+     * Holds data needed to draw each entry in the graph.
+     */
+    private static class GraphValue {
+        /** Position. */
+        float mPos;
+        /** Time when this value was added. */
+        long mTime;
+
+        GraphValue(float pos, long time) {
+            this.mPos = pos;
+            this.mTime = time;
+        }
+    }
+
+    /**
+     * Holds the graph values as a cyclic buffer. It has a fixed capacity, and it replaces the
+     * old values with new ones to avoid creating new objects.
+     */
+    private static class CyclicBuffer {
+        private final GraphValue[] mValues;
+        private final int mCapacity;
+        private int mSize = 0;
+        private int mLastIndex = 0;
+
+        // The iteration index and counter are here to make it easier to reset them.
+        /** Determines the value currently pointed by the iterator. */
+        private int mIteratorIndex;
+        /** Counts how many values have been iterated through. */
+        private int mIteratorCount;
+
+        /** Used traverse the values in reverse order. */
+        private final Iterator<GraphValue> mReverseIterator = new Iterator<GraphValue>() {
+            @Override
+            public boolean hasNext() {
+                return mIteratorCount <= mSize;
+            }
+
+            @Override
+            public GraphValue next() {
+                // Returns the value currently pointed by the iterator and moves the iterator to
+                // the previous one.
+                mIteratorCount++;
+                return mValues[(mIteratorIndex-- + mCapacity) % mCapacity];
+            }
+        };
+
+        CyclicBuffer(int capacity) {
+            mCapacity = capacity;
+            mValues = new GraphValue[capacity];
+        }
+
+        /**
+         * Add new graph value. If there is an existing object, we replace its data with the
+         * new one. With this, we re-use old objects instead of creating new ones.
+         */
+        void add(float pos, long time) {
+            mLastIndex = (mLastIndex + 1) % mCapacity;
+            if (mValues[mLastIndex] == null) {
+                mValues[mLastIndex] = new GraphValue(pos, time);
+            } else {
+                final GraphValue oldValue = mValues[mLastIndex];
+                oldValue.mPos = pos;
+                oldValue.mTime = time;
+            }
+
+            // If needed, account for new value in the buffer size.
+            if (mSize != mCapacity) {
+                mSize++;
+            }
+        }
+
+        int getSize() {
+            return mSize;
+        }
+
+        GraphValue getFirst() {
+            final int distanceBetweenLastAndFirst = (mCapacity - mSize) + 1;
+            final int firstIndex = (mLastIndex + distanceBetweenLastAndFirst) % mCapacity;
+            return mValues[firstIndex];
+        }
+
+        GraphValue getLast() {
+            return mValues[mLastIndex];
+        }
+
+        void removeFirst() {
+            mSize--;
+        }
+
+        /** Returns an iterator pointing at the last value. */
+        Iterator<GraphValue> reverseIterator() {
+            mIteratorIndex = mLastIndex;
+            mIteratorCount = 1;
+            return mReverseIterator;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/input/debug/RotaryInputValueView.java b/services/core/java/com/android/server/input/debug/RotaryInputValueView.java
new file mode 100644
index 0000000000000000000000000000000000000000..9fadac57cef941e7ba324e9e3ea63f2831634acb
--- /dev/null
+++ b/services/core/java/com/android/server/input/debug/RotaryInputValueView.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 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.server.input.debug;
+
+import static android.util.TypedValue.COMPLEX_UNIT_SP;
+
+import android.content.Context;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Typeface;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewConfiguration;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+import java.util.Locale;
+
+/**
+ * Draws the most recent rotary input value and indicates whether the source is active.
+ */
+public class RotaryInputValueView extends TextView {
+
+    private static final int INACTIVE_TEXT_COLOR = 0xffff00ff;
+    private static final int ACTIVE_TEXT_COLOR = 0xff420f28;
+    private static final int TEXT_SIZE_SP = 8;
+    private static final int SIDE_PADDING_SP = 4;
+    /** Determines how long the active status lasts. */
+    private static final int ACTIVE_STATUS_DURATION = 250 /* milliseconds */;
+    private static final ColorFilter ACTIVE_BACKGROUND_FILTER =
+            new ColorMatrixColorFilter(new float[]{
+                    0, 0, 0, 0, 255, // red
+                    0, 0, 0, 0,   0, // green
+                    0, 0, 0, 0, 255, // blue
+                    0, 0, 0, 0, 200  // alpha
+            });
+
+    private final Runnable mUpdateActivityStatusCallback = () -> updateActivityStatus(false);
+    private final float mScaledVerticalScrollFactor;
+    private final Locale mDefaultLocale = Locale.getDefault();
+
+    public RotaryInputValueView(Context c) {
+        super(c);
+
+        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+        mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
+
+        setText(getFormattedValue(0));
+        setTextColor(INACTIVE_TEXT_COLOR);
+        setTextSize(applyDimensionSp(TEXT_SIZE_SP, dm));
+        setPaddingRelative(applyDimensionSp(SIDE_PADDING_SP, dm), 0,
+                applyDimensionSp(SIDE_PADDING_SP, dm), 0);
+        setTypeface(null, Typeface.BOLD);
+        setBackgroundResource(R.drawable.focus_event_rotary_input_background);
+    }
+
+    /** Updates the shown text with the formatted value. */
+    public void updateValue(float value) {
+        removeCallbacks(mUpdateActivityStatusCallback);
+
+        setText(getFormattedValue(value * mScaledVerticalScrollFactor));
+
+        updateActivityStatus(true);
+        postDelayed(mUpdateActivityStatusCallback, ACTIVE_STATUS_DURATION);
+    }
+
+    /** Updates whether or not there's active rotary input. */
+    public void updateActivityStatus(boolean active) {
+        if (active) {
+            setTextColor(ACTIVE_TEXT_COLOR);
+            getBackground().setColorFilter(ACTIVE_BACKGROUND_FILTER);
+        } else {
+            setTextColor(INACTIVE_TEXT_COLOR);
+            getBackground().clearColorFilter();
+        }
+    }
+
+    private String getFormattedValue(float value) {
+        return String.format(mDefaultLocale, "%s%.1f", value < 0 ? "-" : "+", Math.abs(value));
+    }
+
+    /**
+     * Converts a dimension in scaled pixel units to integer display pixels.
+     */
+    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) {
+        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm);
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 7726f40fa2aef75843c19588fdc3a97865e52f5e..dbbbed31df769b6e223d36ad1fb0811cddfcaeb8 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -57,13 +57,13 @@ final class HandwritingEventReceiverSurface {
                 InputConfig.NOT_FOCUSABLE
                         | InputConfig.NOT_TOUCHABLE
                         | InputConfig.SPY
-                        | InputConfig.INTERCEPTS_STYLUS
-                        | InputConfig.TRUSTED_OVERLAY;
+                        | InputConfig.INTERCEPTS_STYLUS;
 
         // Configure the surface to receive stylus events across the entire display.
         mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
 
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
         t.setPosition(mInputSurface, 0, 0);
diff --git a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
index 4335a1dcfa75701c59c281261d8e03ddda37cafe..e1a07076cb2d8d16b96ba5a52a51dbcf77d14982 100644
--- a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
+++ b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
@@ -29,7 +29,12 @@ import android.util.Slog;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 
-import java.util.Calendar;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
 
 /**
  * This service runs everyday at 2am local time to remove expired bitmaps.
@@ -69,26 +74,25 @@ public class NotificationBitmapJobService extends JobService {
      * @return Milliseconds until the next time the job should run.
      */
     private static long getRunAfterMs() {
-        Calendar cal = Calendar.getInstance();  // Uses local time zone
-        final long now = cal.getTimeInMillis();
+        ZoneId zoneId = ZoneId.systemDefault();
+        ZonedDateTime now = Instant.now().atZone(zoneId);
 
-        cal.set(Calendar.HOUR_OF_DAY, 2);
-        cal.set(Calendar.MINUTE, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-        final long today2AM = cal.getTimeInMillis();
+        LocalDate today = now.toLocalDate();
+        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0);
 
-        cal.add(Calendar.DAY_OF_YEAR, 1);
-        final long tomorrow2AM = cal.getTimeInMillis();
+        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId);
+        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);
 
         return getTimeUntilRemoval(now, today2AM, tomorrow2AM);
     }
 
     @VisibleForTesting
-    static long getTimeUntilRemoval(long now, long today2AM, long tomorrow2AM) {
-        if (now < today2AM) {
-            return today2AM - now;
+    static long getTimeUntilRemoval(ZonedDateTime now, ZonedDateTime today2AM,
+                                    ZonedDateTime tomorrow2AM) {
+        if (Duration.between(now, today2AM).isNegative()) {
+            return Duration.between(now, tomorrow2AM).toMillis();
         }
-        return tomorrow2AM - now;
+        return Duration.between(now, today2AM).toMillis();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryJobService.java b/services/core/java/com/android/server/notification/NotificationHistoryJobService.java
index 3776ad7a0799d6b2bea580c2f6cc3dafa8e270d7..c9317d17be37a0eda4f60d06c5b26ae21f5a5898 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryJobService.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryJobService.java
@@ -27,6 +27,7 @@ import android.content.Context;
 import android.os.CancellationSignal;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 
 import java.util.concurrent.TimeUnit;
@@ -77,5 +78,11 @@ public class NotificationHistoryJobService extends JobService {
         }
         return false;
     }
+
+    @Override
+    @VisibleForTesting
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+    }
 }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index db69d93583d4c2a03d9ca5c278cc7d399abea499..87c30674bfb7bd7ea9b74001e02f7af525696766 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -396,7 +396,7 @@ public class NotificationManagerService extends SystemService {
     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
     static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
 
-    static final long BITMAP_EXPIRATION_TIME_MS = TimeUnit.HOURS.toMillis(24);
+    static final Duration BITMAP_DURATION = Duration.ofHours(24);
 
     // ranking thread messages
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
@@ -6705,7 +6705,7 @@ public class NotificationManagerService extends SystemService {
                     final long timePostedMs = r.getSbn().getPostTime();
                     final long timeNowMs = System.currentTimeMillis();
 
-                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_EXPIRATION_TIME_MS)) {
+                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_DURATION.toMillis())) {
                         removeBitmapAndRepost(r);
                     }
                 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 82d3e9157986e1a41b0fa76cb75979bb1c006ae9..68a8e40d052829ae0a0b7c5e4e98ff7fecdad46e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -286,6 +286,8 @@ public class UserManagerService extends IUserManager.Stub {
 
     private static final int USER_VERSION = 11;
 
+    private static final int MAX_USER_STRING_LENGTH = 500;
+
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
     static final int WRITE_USER_MSG = 1;
@@ -4374,15 +4376,17 @@ public class UserManagerService extends IUserManager.Stub {
         // Write seed data
         if (userData.persistSeedData) {
             if (userData.seedAccountName != null) {
-                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
+                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME,
+                        truncateString(userData.seedAccountName));
             }
             if (userData.seedAccountType != null) {
-                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
+                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE,
+                        truncateString(userData.seedAccountType));
             }
         }
         if (userInfo.name != null) {
             serializer.startTag(null, TAG_NAME);
-            serializer.text(userInfo.name);
+            serializer.text(truncateString(userInfo.name));
             serializer.endTag(null, TAG_NAME);
         }
         synchronized (mRestrictionsLock) {
@@ -4431,6 +4435,13 @@ public class UserManagerService extends IUserManager.Stub {
         serializer.endDocument();
     }
 
+    private String truncateString(String original) {
+        if (original == null || original.length() <= MAX_USER_STRING_LENGTH) {
+            return original;
+        }
+        return original.substring(0, MAX_USER_STRING_LENGTH);
+    }
+
     /*
      * Writes the user list file in this format:
      *
@@ -4869,7 +4880,7 @@ public class UserManagerService extends IUserManager.Stub {
             @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
             @NonNull TimingsTraceAndSlog t, @Nullable Object token)
             throws UserManager.CheckedUserOperationException {
-
+        String truncatedName = truncateString(name);
         final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
         if (userTypeDetails == null) {
             throwCheckedUserOperationException(
@@ -4904,8 +4915,8 @@ public class UserManagerService extends IUserManager.Stub {
 
         // Try to use a pre-created user (if available).
         if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
-            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name,
-                    token);
+            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags,
+                    truncatedName, token);
             if (preCreatedUser != null) {
                 return preCreatedUser;
             }
@@ -5000,7 +5011,7 @@ public class UserManagerService extends IUserManager.Stub {
                         flags |= UserInfo.FLAG_EPHEMERAL_ON_CREATE;
                     }
 
-                    userInfo = new UserInfo(userId, name, null, flags, userType);
+                    userInfo = new UserInfo(userId, truncatedName, null, flags, userType);
                     userInfo.serialNumber = mNextSerialNumber++;
                     userInfo.creationTime = getCreationTime();
                     userInfo.partial = true;
@@ -6456,8 +6467,8 @@ public class UserManagerService extends IUserManager.Stub {
                     Slog.e(LOG_TAG, "No such user for settings seed data u=" + userId);
                     return;
                 }
-                userData.seedAccountName = accountName;
-                userData.seedAccountType = accountType;
+                userData.seedAccountName = truncateString(accountName);
+                userData.seedAccountType = truncateString(accountType);
                 userData.seedAccountOptions = accountOptions;
                 userData.persistSeedData = persist;
             }
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index ebc7163cd05ccdfebbc236ed7361f92d5d5a491b..b83421fe78d795f17d59d380d10b5b46eb4d6ed1 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -42,6 +42,7 @@ import android.os.PackageTagsList;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.permission.flags.Flags;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
 import android.text.TextUtils;
@@ -75,9 +76,6 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
     private static final boolean SYSPROP_HOTWORD_DETECTION_SERVICE_REQUIRED =
             SystemProperties.getBoolean("ro.hotword.detection_service_required", false);
 
-    //TODO(b/289087412): import this from the flag value in set up in device config.
-    private static final boolean IS_VOICE_ACTIVATION_OP_ENABLED = false;
-
     @NonNull
     private final Object mLock = new Object();
 
@@ -212,7 +210,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
      * @return the op that should be noted for the voice activations of the app by detected hotword.
      */
     public static int getVoiceActivationOp() {
-        if (IS_VOICE_ACTIVATION_OP_ENABLED) {
+        if (Flags.voiceActivationPermissionApis()) {
             return OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
         }
         return OP_RECORD_AUDIO_HOTWORD;
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index c39b266a7701c498da73c8dea86b2ed118cf944f..4a5311b14397e45529f91a0ed04e02b193ec7aa1 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -577,7 +577,8 @@ public class ActivityStartController {
                 .getRootTask(WINDOWING_MODE_UNDEFINED, activityType);
         if (rootTask == null) return false;
         final ActivityRecord r = rootTask.topRunningActivity();
-        if (r == null || r.isVisibleRequested() || !r.attachedToProcess()
+        if (r == null || (r.isVisibleRequested() && rootTask.isTopRootTaskInDisplayArea())
+                || !r.attachedToProcess()
                 || !r.mActivityComponent.equals(intent.getComponent())
                 || !mService.isCallerRecents(r.getUid())
                 // Recents keeps invisible while device is locked.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 61bae7153f6da7341670808e00971072d0339bd0..0b673211a1c9ced5b822726e24c311edf5edd663 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6448,19 +6448,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                 if (!restarting && hasVisibleActivities) {
                     deferWindowLayout();
                     try {
-                        final Task topTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
-                        if (topTask != null
-                                && topTask.topRunningActivity(true /* focusableOnly */) == null) {
-                            topTask.adjustFocusToNextFocusableTask("handleAppDied");
-                        }
-                        if (!mRootWindowContainer.resumeFocusedTasksTopActivities()) {
-                            // If there was nothing to resume, and we are not already restarting
-                            // this process, but there is a visible activity that is hosted by the
-                            // process...then make sure all visible activities are running, taking
-                            // care of restarting this process.
-                            mRootWindowContainer.ensureActivitiesVisible(null, 0,
-                                    !PRESERVE_WINDOWS);
-                        }
+                        mRootWindowContainer.ensureVisibilityOnVisibleActivityDiedOrCrashed(
+                                "handleAppDied");
                     } finally {
                         continueWindowLayout();
                     }
@@ -6901,7 +6890,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         @Override
         public int finishTopCrashedActivities(WindowProcessController crashedApp, String reason) {
             synchronized (mGlobalLock) {
-                return mRootWindowContainer.finishTopCrashedActivities(crashedApp, reason);
+                deferWindowLayout();
+                try {
+                    final Task finishedTask = mRootWindowContainer.finishTopCrashedActivities(
+                            crashedApp, reason);
+                    if (finishedTask != null) {
+                        mRootWindowContainer.ensureVisibilityOnVisibleActivityDiedOrCrashed(reason);
+                        return finishedTask.mTaskId;
+                    }
+                    return INVALID_TASK_ID;
+                } finally {
+                    continueWindowLayout();
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0f1a1053716e6d8d4c698c6c650f9de0d2f1a607..7af4aadb2f0e6a34ead5a6757c586acc73b41d7e 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -48,7 +48,6 @@ import android.hardware.input.InputManagerGlobal;
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.os.InputConfig;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -186,6 +185,10 @@ class DragState {
         // Crop the input surface to the display size.
         mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
 
+        // Make trusted overlay to not block any touches while D&D ongoing and allowing
+        // touches to pass through to windows underneath. This allows user to interact with the
+        // UI to navigate while dragging.
+        h.setTrustedOverlay(mTransaction, mInputSurface, true);
         mTransaction.show(mInputSurface)
                 .setInputWindowInfo(mInputSurface, h)
                 .setLayer(mInputSurface, Integer.MAX_VALUE)
@@ -377,11 +380,6 @@ class DragState {
             mDragWindowHandle.ownerUid = MY_UID;
             mDragWindowHandle.scaleFactor = 1.0f;
 
-            // InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing
-            // touches to pass through to windows underneath. This allows user to interact with the
-            // UI to navigate while dragging.
-            mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY;
-
             // The drag window cannot receive new touches.
             mDragWindowHandle.touchableRegion.setEmpty();
 
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 39622c1c5aaf2d61e59d7898f5a9dc38362ea468..c21930dab5ebe68502ef07f27d32a091da849634 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -74,7 +74,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
         mWindowHandle.ownerPid = WindowManagerService.MY_PID;
         mWindowHandle.ownerUid = WindowManagerService.MY_UID;
         mWindowHandle.scaleFactor = 1.0f;
-        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY;
+        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
 
         mInputSurface = mService.makeSurfaceBuilder(
                         mService.mRoot.getDisplayContent(displayId).getSession())
@@ -129,12 +129,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
 
     void show(SurfaceControl.Transaction t, WindowContainer w) {
         t.show(mInputSurface);
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);
     }
 
     void show(SurfaceControl.Transaction t, int layer) {
         t.show(mInputSurface);
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, layer);
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 825d38b3eed746bfa8177d7a5a6a608d4821e26c..af307ec3c2a9623c7fcf7ca51665fd04e59c4be1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -675,6 +675,11 @@ final class InputMonitor {
                     w.getKeyInterceptionInfo());
 
             if (w.mWinAnimator.hasSurface()) {
+                // Update trusted overlay changes here because they are tied to input info. Input
+                // changes can be updated even if surfaces aren't.
+                inputWindowHandle.setTrustedOverlay(mInputTransaction,
+                        w.mWinAnimator.mSurfaceController.mSurfaceControl,
+                        w.isWindowTrustedOverlay());
                 populateInputWindowHandle(inputWindowHandle, w);
                 setInputWindowInfoIfNeeded(mInputTransaction,
                         w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
@@ -732,7 +737,7 @@ final class InputMonitor {
                 new InputWindowHandle(null /* inputApplicationHandle */, displayId));
         inputWindowHandle.setName(name);
         inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
-        inputWindowHandle.setTrustedOverlay(true);
+        inputWindowHandle.setTrustedOverlay(t, sc, true);
         populateOverlayInputInfo(inputWindowHandle);
         setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
     }
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index 64b7a6064e4578aea327f438c613a10b4c60b1ac..90d81bd82087251922f85c6ad5c3a5328415854f 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -195,6 +195,11 @@ class InputWindowHandleWrapper {
         mChanged = true;
     }
 
+    void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc,
+            boolean trustedOverlay) {
+        mHandle.setTrustedOverlay(t, sc, trustedOverlay);
+    }
+
     void setOwnerPid(int pid) {
         if (mHandle.ownerPid == pid) {
             return;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index c3977d6918e35fe83f2005c62ae7bda91bd92326..82d4b90d06be33ffa69bb086d656e1feae1aa327 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -62,6 +62,7 @@ import android.window.PictureInPictureSurfaceTransaction;
 import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -244,7 +245,8 @@ public class RecentsAnimationController implements DeathRecipient {
         }
 
         @Override
-        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
+        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint,
+                IResultReceiver finishCb) {
             ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                     "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled);
             final long token = Binder.clearCallingIdentity();
@@ -257,6 +259,13 @@ public class RecentsAnimationController implements DeathRecipient {
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
+            if (finishCb != null) {
+                try {
+                    finishCb.send(0, new Bundle());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to report animation finished", e);
+                }
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a88aa2e3f78062870439ef5f06a11734978d955b..cf6a1feef5ee90c97481dffb8b4ef67084b7a941 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2319,19 +2319,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
      *
      * @param app    The app that crashed.
      * @param reason Reason to perform this action.
-     * @return The task id that was finished in this root task, or INVALID_TASK_ID if none was
-     * finished.
+     * @return The finished task which was on top or visible, otherwise {@code null} if the crashed
+     *         app doesn't have activity in visible task.
      */
-    int finishTopCrashedActivities(WindowProcessController app, String reason) {
+    @Nullable
+    Task finishTopCrashedActivities(WindowProcessController app, String reason) {
         Task focusedRootTask = getTopDisplayFocusedRootTask();
         final Task[] finishedTask = new Task[1];
         forAllRootTasks(rootTask -> {
+            final boolean recordTopOrVisible = finishedTask[0] == null
+                    && (focusedRootTask == rootTask || rootTask.isVisibleRequested());
             final Task t = rootTask.finishTopCrashedActivityLocked(app, reason);
-            if (rootTask == focusedRootTask || finishedTask[0] == null) {
+            if (recordTopOrVisible) {
                 finishedTask[0] = t;
             }
         });
-        return finishedTask[0] != null ? finishedTask[0].mTaskId : INVALID_TASK_ID;
+        return finishedTask[0];
+    }
+
+    void ensureVisibilityOnVisibleActivityDiedOrCrashed(String reason) {
+        final Task topTask = getTopDisplayFocusedRootTask();
+        if (topTask != null && topTask.topRunningActivity(true /* focusableOnly */) == null) {
+            // Move the next focusable task to front.
+            topTask.adjustFocusToNextFocusableTask(reason);
+        }
+        if (!resumeFocusedTasksTopActivities()) {
+            // It may be nothing to resume because there are pausing activities or all the top
+            // activities are resumed. Then it still needs to make sure all visible activities are
+            // running in case the tasks were reordered or there are non-top visible activities.
+            ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS);
+        }
     }
 
     boolean resumeFocusedTasksTopActivities() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c6547a0c11b82250487d96f4726b96bf766708a2..882104a297efaa61a29a4ded588ea75f56120856 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -372,8 +372,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
             parent.forAllTasks(t -> {
                 // Skip transient-launch task
                 if (t == transientRootTask) return false;
-                if (t.isVisibleRequested() && !t.isAlwaysOnTop()
-                        && !t.getWindowConfiguration().tasksAreFloating()) {
+                if (t.isVisibleRequested() && !t.isAlwaysOnTop()) {
                     if (t.isRootTask()) {
                         mTransientHideTasks.add(t);
                     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1996dd9068f29d7fa70dee66d816601230344c7e..074b4044fdaabfb398849c60eb3af8d1c130db85 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2493,14 +2493,6 @@ public class WindowManagerService extends IWindowManager.Stub
                 outInsetsState.set(win.getCompatInsetsState(), true /* copySources */);
             }
 
-            // TODO (b/298562855): Remove this after identifying the reason why the frame is empty.
-            if (win.mAttrs.providedInsets != null && win.getFrame().isEmpty()) {
-                Slog.w(TAG, "Empty frame of " + win
-                        + " configChanged=" + configChanged
-                        + " frame=" + win.getFrame().toShortString()
-                        + " attrs=" + attrs);
-            }
-
             ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
                     win, focusMayChange);
 
@@ -8884,11 +8876,6 @@ public class WindowManagerService extends IWindowManager.Stub
             h.inputConfig |= InputConfig.NOT_FOCUSABLE;
         }
 
-        //  Check private trusted overlay flag to set trustedOverlay field of input window handle.
-        if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
-            h.inputConfig |= InputConfig.TRUSTED_OVERLAY;
-        }
-
         h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         h.ownerUid = callingUid;
         h.ownerPid = callingPid;
@@ -8908,6 +8895,8 @@ public class WindowManagerService extends IWindowManager.Stub
         }
 
         final SurfaceControl.Transaction t = mTransactionFactory.get();
+        //  Check private trusted overlay flag to set trustedOverlay field of input window handle.
+        h.setTrustedOverlay(t, surface, (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0);
         t.setInputWindowInfo(surface, h);
         t.apply();
         t.close();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ebef606a8d603bb05af60fb7f2d37c400dacdefc..4beec2bc79e6f1d380673bb65d59745a03975563 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -178,6 +178,7 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE
 import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
 import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
+import static com.android.window.flags.Flags.surfaceTrustedOverlay;
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
@@ -1110,7 +1111,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         mInputWindowHandle.setName(getName());
         mInputWindowHandle.setPackageName(mAttrs.packageName);
         mInputWindowHandle.setLayoutParamsType(mAttrs.type);
-        mInputWindowHandle.setTrustedOverlay(shouldWindowHandleBeTrusted(s));
+        if (!surfaceTrustedOverlay()) {
+            mInputWindowHandle.setTrustedOverlay(isWindowTrustedOverlay());
+        }
         if (DEBUG) {
             Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
                             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -1185,12 +1188,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         }
     }
 
-    boolean shouldWindowHandleBeTrusted(Session s) {
+    public boolean isWindowTrustedOverlay() {
         return InputMonitor.isTrustedOverlay(mAttrs.type)
                 || ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
-                        && s.mCanAddInternalSystemWindow)
+                        && mSession.mCanAddInternalSystemWindow)
                 || ((mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0
-                        && s.mCanCreateSystemApplicationOverlay);
+                        && mSession.mCanCreateSystemApplicationOverlay);
     }
 
     int getTouchOcclusionMode() {
@@ -5187,6 +5190,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
             updateFrameRateSelectionPriorityIfNeeded();
             updateScaleIfNeeded();
             mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
+            if (surfaceTrustedOverlay()) {
+                getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay());
+            }
         }
         super.prepareSurfaces();
     }
@@ -5939,7 +5945,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
     }
 
     boolean isTrustedOverlay() {
-        return mInputWindowHandle.isTrustedOverlay();
+        if (surfaceTrustedOverlay()) {
+            WindowState parentWindow = getParentWindow();
+            return isWindowTrustedOverlay() || (parentWindow != null
+                    && parentWindow.isWindowTrustedOverlay());
+        } else {
+            return mInputWindowHandle.isTrustedOverlay();
+        }
     }
 
     public boolean receiveFocusFromTapOutside() {
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index d0a9c458a20f7fa58603106c88fcde25761da398..debd891400b6d540f7d4ef5426a0005665d4ad39 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -46,6 +46,8 @@
                     <xs:annotation name="nonnull"/>
                     <xs:annotation name="final"/>
                 </xs:element>
+                <xs:element type="powerThrottlingConfig" name="powerThrottlingConfig" minOccurs="0"
+                            maxOccurs="1"/>
                 <xs:element type="luxThrottling" name="luxThrottling" minOccurs="0"
                             maxOccurs="1"/>
                 <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0"
@@ -350,6 +352,43 @@
         </xs:sequence>
     </xs:complexType>
 
+    <xs:complexType name="powerThrottlingMap">
+        <xs:sequence>
+            <xs:element name="powerThrottlingPoint" type="powerThrottlingPoint" maxOccurs="unbounded" minOccurs="1">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+        <xs:attribute name="id" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="powerThrottlingPoint">
+        <xs:sequence>
+            <xs:element type="thermalStatus" name="thermalStatus">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+            <xs:element type="nonNegativeDecimal" name="powerQuotaMilliWatts">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="powerThrottlingConfig">
+        <xs:element type="nonNegativeDecimal" name="brightnessLowestCapAllowed">
+            <xs:annotation name="nonnull"/>
+            <xs:annotation name="final"/>
+        </xs:element>
+        <xs:element name="pollingWindowMillis" type="xs:nonNegativeInteger">
+            <xs:annotation name="nonnull"/>
+            <xs:annotation name="final"/>
+        </xs:element>
+        <xs:element type="powerThrottlingMap" name="powerThrottlingMap" maxOccurs="unbounded">
+                <xs:annotation name="final"/>
+        </xs:element>
+    </xs:complexType>
+
     <xs:complexType name="nitsMap">
         <xs:sequence>
             <xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 949b1f2cb74b955ef19a9f4e9b38363148f0be56..2d27f0c7966082bb94e29736396fbd728e0889a8 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -106,6 +106,7 @@ package com.android.server.display.config {
     method public final com.android.server.display.config.SensorDetails getLightSensor();
     method public com.android.server.display.config.LuxThrottling getLuxThrottling();
     method @Nullable public final String getName();
+    method public com.android.server.display.config.PowerThrottlingConfig getPowerThrottlingConfig();
     method public final com.android.server.display.config.SensorDetails getProxSensor();
     method public com.android.server.display.config.DisplayQuirks getQuirks();
     method public com.android.server.display.config.RefreshRateConfigs getRefreshRate();
@@ -138,6 +139,7 @@ package com.android.server.display.config {
     method public final void setLightSensor(com.android.server.display.config.SensorDetails);
     method public void setLuxThrottling(com.android.server.display.config.LuxThrottling);
     method public final void setName(@Nullable String);
+    method public void setPowerThrottlingConfig(com.android.server.display.config.PowerThrottlingConfig);
     method public final void setProxSensor(com.android.server.display.config.SensorDetails);
     method public void setQuirks(com.android.server.display.config.DisplayQuirks);
     method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs);
@@ -246,6 +248,30 @@ package com.android.server.display.config {
     method public final void setValue(@NonNull java.math.BigDecimal);
   }
 
+  public class PowerThrottlingConfig {
+    ctor public PowerThrottlingConfig();
+    method @NonNull public final java.math.BigDecimal getBrightnessLowestCapAllowed();
+    method @NonNull public final java.math.BigInteger getPollingWindowMillis();
+    method public final java.util.List<com.android.server.display.config.PowerThrottlingMap> getPowerThrottlingMap();
+    method public final void setBrightnessLowestCapAllowed(@NonNull java.math.BigDecimal);
+    method public final void setPollingWindowMillis(@NonNull java.math.BigInteger);
+  }
+
+  public class PowerThrottlingMap {
+    ctor public PowerThrottlingMap();
+    method public String getId();
+    method @NonNull public final java.util.List<com.android.server.display.config.PowerThrottlingPoint> getPowerThrottlingPoint();
+    method public void setId(String);
+  }
+
+  public class PowerThrottlingPoint {
+    ctor public PowerThrottlingPoint();
+    method @NonNull public final java.math.BigDecimal getPowerQuotaMilliWatts();
+    method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus();
+    method public final void setPowerQuotaMilliWatts(@NonNull java.math.BigDecimal);
+    method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus);
+  }
+
   public enum PredefinedBrightnessLimitNames {
     method public String getRawName();
     enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames _default;
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index 57b5d00f75a0e72be51bf325afd14b27d810431c..4e954653bcbb7678ec8e4f01ec7d0ede2cbe9de7 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -52,6 +52,7 @@
             <xs:element name="address" type="xs:nonNegativeInteger"/>
             <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />
             <xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
+            <xs:element name="powerThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
             <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />
             <xs:element name="leadDisplayAddress" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" />
         </xs:sequence>
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index 2d4f7a428db127874dac2c4f1aca842e36236303..195cae5aee14e9156a6ba4a5440f64e7d49edb08 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -8,6 +8,7 @@ package com.android.server.display.config.layout {
     method public String getDisplayGroup();
     method public java.math.BigInteger getLeadDisplayAddress();
     method public String getPosition();
+    method public String getPowerThrottlingMapId();
     method public String getRefreshRateThermalThrottlingMapId();
     method public String getRefreshRateZoneId();
     method public boolean isDefaultDisplay();
@@ -19,6 +20,7 @@ package com.android.server.display.config.layout {
     method public void setEnabled(boolean);
     method public void setLeadDisplayAddress(java.math.BigInteger);
     method public void setPosition(String);
+    method public void setPowerThrottlingMapId(String);
     method public void setRefreshRateThermalThrottlingMapId(String);
     method public void setRefreshRateZoneId(String);
   }
diff --git a/services/foldables/devicestateprovider/tests/Android.bp b/services/foldables/devicestateprovider/tests/Android.bp
index a8db05e9917945e42e5c379526bb41ac0db18dd7..84a6df38e0a0c01f8ae9d9d348ca7bef32c1c95a 100644
--- a/services/foldables/devicestateprovider/tests/Android.bp
+++ b/services/foldables/devicestateprovider/tests/Android.bp
@@ -20,11 +20,11 @@ android_test {
         "foldable-device-state-provider",
         "androidx.test.rules",
         "junit",
-        "truth-prebuilt",
+        "truth",
         "mockito-target-extended-minus-junit4",
         "androidx.test.uiautomator_uiautomator",
         "androidx.test.ext.junit",
         "testables",
     ],
-    test_suites: ["device-tests"]
+    test_suites: ["device-tests"],
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 57fa12d20de510f35c5ef98269f04991642d46ed..49ad84a8e6d9954f799e34ee5f6973d9a414f67d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -264,6 +264,8 @@ public final class SystemServer implements Dumpable {
             "com.android.server.backup.BackupManagerService$Lifecycle";
     private static final String APPWIDGET_SERVICE_CLASS =
             "com.android.server.appwidget.AppWidgetService";
+    private static final String ARC_SYSTEM_HEALTH_SERVICE =
+            "com.android.server.arc.health.ArcSystemHealthService";
     private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
             "com.android.server.voiceinteraction.VoiceInteractionManagerService";
     private static final String APP_HIBERNATION_SERVICE_CLASS =
@@ -1287,6 +1289,12 @@ public final class SystemServer implements Dumpable {
             }
         }
 
+        if (Build.IS_ARC) {
+            t.traceBegin("StartArcSystemHealthService");
+            mSystemServiceManager.startService(ARC_SYSTEM_HEALTH_SERVICE);
+            t.traceEnd();
+        }
+
         t.traceBegin("StartUserManagerService");
         mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
         t.traceEnd();
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index e04dd688f2a2bcfc15fb86adbe05d165417c18a4..8b9efb312efe48c5a4c9b8fc40716f4efc446db7 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -59,7 +59,7 @@ android_robolectric_test {
         "mockito-robolectric-prebuilt",
         "platform-test-annotations",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
 
     instrumentation_for: "BackupFrameworksServicesLib",
diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp
index 36446f64bdce92fb2e0b7d7aa04c8a4810152fa2..ffe6dc5d1c63bae131f6687bb266513b9463a356 100644
--- a/services/tests/InputMethodSystemServerTests/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/Android.bp
@@ -44,7 +44,7 @@ android_test {
         "service-permission.stubs.system_server",
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
@@ -92,7 +92,7 @@ android_test {
         "service-permission.stubs.system_server",
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
-        "truth-prebuilt",
+        "truth",
         "SimpleImeTestingLib",
         "SimpleImeImsLib",
     ],
diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp
index 35d754b4adc5952bea0151655178ad2cbae9703f..e8fce8e72601e2e81ecd155fff181989462cb6ad 100644
--- a/services/tests/PackageManager/packageinstaller/Android.bp
+++ b/services/tests/PackageManager/packageinstaller/Android.bp
@@ -32,7 +32,7 @@ android_test {
         "androidx.test.runner",
         "junit",
         "kotlin-test",
-        "truth-prebuilt",
+        "truth",
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
diff --git a/services/tests/PackageManagerComponentOverrideTests/Android.bp b/services/tests/PackageManagerComponentOverrideTests/Android.bp
index bc369701b2d443ee88d37cdfc8684b0308a5a13a..00850a5e5be0f4600dd611647ef8bd36bb4a1a60 100644
--- a/services/tests/PackageManagerComponentOverrideTests/Android.bp
+++ b/services/tests/PackageManagerComponentOverrideTests/Android.bp
@@ -38,7 +38,7 @@ android_test {
         "service-permission.stubs.system_server",
         "servicestests-utils-mockito-extended",
         "testng", // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
-        "truth-prebuilt",
+        "truth",
     ],
 
     jni_libs: [
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 9c4e6fd66cebce24134c2cf0cc67f3635a6c4cc1..ad7af44d4089a95abc2da45e38add284e9edf0e3 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -29,7 +29,7 @@ android_test {
     static_libs: [
         "compatibility-device-util-axt",
         "androidx.test.runner",
-        "truth-prebuilt",
+        "truth",
         "Harrier",
     ],
     platform_apis: true,
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index ce28682c0a2555232df5ea6ca095ea50c30d12ac..6eacef767042156486cb599ea050b97114c20e77 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -30,7 +30,7 @@ java_test_host {
     libs: [
         "tradefed",
         "junit",
-        "truth-prebuilt",
+        "truth",
     ],
     static_libs: [
         "ApexInstallHelper",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 462c5801e95290fb93a6534cce3384c367400e8c..cea9c599317de703eb3d7de3d479aaeb2b0a82a1 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -38,6 +38,6 @@ android_test_helper_app {
         "junit-params",
         "androidx.test.ext.junit",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
index 57184748d074a3489d2e098ccd873fd6454fc31d..ed5f2b51b9ed3767396952d8e85654cc522a6a9a 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
@@ -28,6 +28,6 @@ android_test_helper_app {
         "androidx.test.runner",
         "junit",
         "kotlin-test",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index a1d846e0f426ada5482589380cbf7524b6c2ce4d..3aca1cafbf751a4e0c38967fbdc939d7815cbede 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -41,7 +41,7 @@ android_test {
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "ShortcutManagerTestUtils",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "platformprotosnano",
         "framework-protos",
@@ -51,7 +51,7 @@ android_test {
         "servicestests-utils",
         "service-permission.impl",
         "testng",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "junit-params",
         "platform-compat-test-rules",
diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp
index 9b3b8c35736c5be09759d9524cd0dc47391fd410..8505983894a827c2da616ade28952facd020d306 100644
--- a/services/tests/PackageManagerServiceTests/unit/Android.bp
+++ b/services/tests/PackageManagerServiceTests/unit/Android.bp
@@ -37,7 +37,7 @@ android_test {
         "services.core",
         "servicestests-utils",
         "servicestests-core-utils",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         "libdexmakerjvmtiagent",
diff --git a/services/tests/RemoteProvisioningServiceTests/Android.bp b/services/tests/RemoteProvisioningServiceTests/Android.bp
index fc2c0857146bfe0e0e937dc42962b9541f6c7585..19c913620760a110abac4529e41930b9f7ab0c98 100644
--- a/services/tests/RemoteProvisioningServiceTests/Android.bp
+++ b/services/tests/RemoteProvisioningServiceTests/Android.bp
@@ -30,8 +30,8 @@ android_test {
         "mockito-target",
         "service-rkp.impl",
         "services.core",
-        "truth-prebuilt",
-        "truth-java8-extension-jar",
+        "truth",
+        "truth-java8-extension",
     ],
     test_suites: [
         "device-tests",
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
index e724e804f4e7e24e29a9d79db45347e417224512..9dacfeabf1ef3b7ad36ccdceef0548caf6d903f4 100644
--- a/services/tests/apexsystemservices/Android.bp
+++ b/services/tests/apexsystemservices/Android.bp
@@ -34,7 +34,7 @@ java_test_host {
         "compatibility-host-util",
         "cts-install-lib-host",
         "frameworks-base-hostutils",
-        "truth-prebuilt",
+        "truth",
         "modules-utils-build-testing",
     ],
     test_suites: [
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 6ef150c80037ca71719a9bae0d77ec67fbfe4af1..c37d21ae1cc05de3114a19f15cc1bca15482f261 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -178,6 +178,89 @@ public final class DisplayDeviceConfigTest {
         assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
     }
 
+    @Test
+    public void testPowerThrottlingConfigFromDisplayConfig() throws IOException {
+        setupDisplayDeviceConfigFromDisplayConfigFile();
+
+        DisplayDeviceConfig.PowerThrottlingConfigData powerThrottlingConfigData =
+                mDisplayDeviceConfig.getPowerThrottlingConfigData();
+        assertNotNull(powerThrottlingConfigData);
+        assertEquals(0.1f, powerThrottlingConfigData.brightnessLowestCapAllowed, SMALL_DELTA);
+        assertEquals(10, powerThrottlingConfigData.pollingWindowMillis);
+    }
+
+    @Test
+    public void testPowerThrottlingDataFromDisplayConfig() throws IOException {
+        setupDisplayDeviceConfigFromDisplayConfigFile();
+
+        List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel>
+                defaultThrottlingLevels = new ArrayList<>();
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f
+                ));
+
+        DisplayDeviceConfig.PowerThrottlingData defaultThrottlingData =
+                new DisplayDeviceConfig.PowerThrottlingData(defaultThrottlingLevels);
+
+        List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel>
+                concurrentThrottlingLevels = new ArrayList<>();
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f
+                ));
+        DisplayDeviceConfig.PowerThrottlingData concurrentThrottlingData =
+                new DisplayDeviceConfig.PowerThrottlingData(concurrentThrottlingLevels);
+
+        HashMap<String, DisplayDeviceConfig.PowerThrottlingData> throttlingDataMap =
+                new HashMap<>(2);
+        throttlingDataMap.put("default", defaultThrottlingData);
+        throttlingDataMap.put("concurrent", concurrentThrottlingData);
+
+        assertEquals(throttlingDataMap,
+                mDisplayDeviceConfig.getPowerThrottlingDataMapByThrottlingId());
+    }
+
     @Test
     public void testConfigValuesFromConfigResource() {
         setupDisplayDeviceConfigFromConfigResourceFile();
@@ -845,6 +928,64 @@ public final class DisplayDeviceConfigTest {
                 +   "</screenBrightnessRampSlowIncreaseIdle>\n";
     }
 
+    private String getPowerThrottlingConfig() {
+        return  "<powerThrottlingConfig >\n"
+                +       "<brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>\n"
+                +       "<pollingWindowMillis>10</pollingWindowMillis>\n"
+                +       "<powerThrottlingMap>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>light</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n"
+                +        "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>moderate</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>severe</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>critical</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>emergency</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>shutdown</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +       "</powerThrottlingMap>\n"
+                +       "<powerThrottlingMap id=\"concurrent\">\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>light</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>moderate</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>severe</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>critical</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>emergency</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>shutdown</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +       "</powerThrottlingMap>\n"
+                +   "</powerThrottlingConfig>\n";
+    }
     private String getScreenBrightnessRampCapsIdle() {
         return "<screenBrightnessRampIncreaseMaxIdleMillis>"
                 +       "4000"
@@ -915,6 +1056,7 @@ public final class DisplayDeviceConfigTest {
                 +            "</displayBrightnessPoint>\n"
                 +       "</displayBrightnessMapping>\n"
                 +   "</autoBrightness>\n"
+                +  getPowerThrottlingConfig()
                 +   "<highBrightnessMode enabled=\"true\">\n"
                 +       "<transitionPoint>" + BRIGHTNESS[1] + "</transitionPoint>\n"
                 +       "<minimumLux>10000</minimumLux>\n"
diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp
index 7c237ac6befb95f804734c66be5975478d79a586..086e84b86aca4a7bc52bb684dbabc1b6344d984b 100644
--- a/services/tests/inprocesstests/Android.bp
+++ b/services/tests/inprocesstests/Android.bp
@@ -14,7 +14,7 @@ android_test {
         "androidx.test.core",
         "androidx.test.rules",
         "services.core",
-        "truth-prebuilt",
+        "truth",
         "platform-test-annotations",
     ],
     test_suites: ["general-tests"],
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 0813bb09fd52ab1f585b52eb9656a4200ded58a2..063af573e1f39562954518916de4db74d54f3ce3 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -68,7 +68,7 @@ android_test {
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
         "testables",
-        "truth-prebuilt",
+        "truth",
         // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
         "testng",
         "compatibility-device-util-axt",
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 5b1508b8393be1e8eff82cb4c40610169d085849..be29163e7677be897877d69389b080735512bf74 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -1290,7 +1290,8 @@ public class DeviceIdleControllerTest {
     }
 
     @Test
-    public void testLightStepIdleStateIdlingTimeIncreases() {
+    public void testLightStepIdleStateIdlingTimeIncreasesExponentially() {
+        mConstants.LIGHT_IDLE_INCREASE_LINEARLY = false;
         final long maintenanceTimeMs = 60_000L;
         mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;
         mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs;
@@ -1335,13 +1336,88 @@ public class DeviceIdleControllerTest {
                 eq(mInjector.nowElapsed + idlingTimeMs),
                 anyLong(), anyString(), any(), any(Handler.class));
 
-        for (int i = 0; i < 2; ++i) {
+        for (int i = 0; i < 10; ++i) {
             // IDLE->MAINTENANCE alarm
             mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
             alarmListener.onAlarm();
             verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
             long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
             idlingTimeMs *= mConstants.LIGHT_IDLE_FACTOR;
+            idlingTimeMs = Math.min(idlingTimeMs, mConstants.LIGHT_MAX_IDLE_TIMEOUT);
+            // Set MAINTENANCE->IDLE
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                    eq(maintenanceExpiryTime),
+                    anyLong(), anyString(), any(), any(Handler.class));
+
+            // MAINTENANCE->IDLE alarm
+            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+            alarmListener.onAlarm();
+            verifyLightStateConditions(LIGHT_STATE_IDLE);
+            // Set IDLE->MAINTENANCE again
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                    eq(mInjector.nowElapsed + idlingTimeMs),
+                    anyLong(), anyString(), any(), any(Handler.class));
+        }
+    }
+
+    @Test
+    public void testLightStepIdleStateIdlingTimeIncreasesLinearly() {
+        mConstants.LIGHT_IDLE_INCREASE_LINEARLY = true;
+        final long maintenanceTimeMs = 60_000L;
+        mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;
+        mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs;
+        mConstants.LIGHT_IDLE_TIMEOUT = 5 * 60_000L;
+        mConstants.LIGHT_MAX_IDLE_TIMEOUT = 30 * 60_000L;
+        mConstants.LIGHT_IDLE_FACTOR = 2f;
+        mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = 2 * 60_000L;
+
+        setNetworkConnected(true);
+        mDeviceIdleController.setJobsActive(false);
+        mDeviceIdleController.setAlarmsActive(false);
+        mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+        InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
+                .forClass(AlarmManager.OnAlarmListener.class);
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+
+        // Set state to INACTIVE.
+        mDeviceIdleController.becomeActiveLocked("testing", 0);
+        setChargingOn(false);
+        setScreenOn(false);
+        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+        long idlingTimeMs = mConstants.LIGHT_IDLE_TIMEOUT;
+        final long idleAfterInactiveExpiryTime =
+                mInjector.nowElapsed + mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                eq(idleAfterInactiveExpiryTime),
+                anyLong(), anyString(), any(), any(Handler.class));
+
+        final AlarmManager.OnAlarmListener alarmListener =
+                alarmListenerCaptor.getAllValues().get(0);
+
+        // INACTIVE -> IDLE alarm
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+        alarmListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE);
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                eq(mInjector.nowElapsed + idlingTimeMs),
+                anyLong(), anyString(), any(), any(Handler.class));
+
+        for (int i = 0; i < 10; ++i) {
+            // IDLE->MAINTENANCE alarm
+            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+            alarmListener.onAlarm();
+            verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+            long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
+            idlingTimeMs += mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS;
+            idlingTimeMs = Math.min(idlingTimeMs, mConstants.LIGHT_MAX_IDLE_TIMEOUT);
             // Set MAINTENANCE->IDLE
             alarmManagerInOrder.verify(mAlarmManager).setWindow(
                     eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6304270f9a7674943fdbeef0b8e199e1c9205c46..305569edd2fa5d32d000703e9d4f1ce49acfa7ee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -308,7 +308,6 @@ public final class UserManagerServiceTest {
         addDefaultProfileAndParent();
 
         mUms.setBootUser(PROFILE_USER_ID);
-
         // Boot user not switchable so return most recently in foreground.
         assertWithMessage("getBootUser")
                 .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID);
@@ -523,6 +522,24 @@ public final class UserManagerServiceTest {
                 .isFalse();
     }
 
+    @Test
+    public void testCreateUserWithLongName_TruncatesName() {
+        UserInfo user = mUms.createUserWithThrow(generateLongString(), USER_TYPE_FULL_SECONDARY, 0);
+        assertThat(user.name.length()).isEqualTo(500);
+        UserInfo user1 = mUms.createUserWithThrow("Test", USER_TYPE_FULL_SECONDARY, 0);
+        assertThat(user1.name.length()).isEqualTo(4);
+    }
+
+    private String generateLongString() {
+        String partialString = "Test Name Test Name Test Name Test Name Test Name Test Name Test "
+                + "Name Test Name Test Name Test Name "; //String of length 100
+        StringBuilder resultString = new StringBuilder();
+        for (int i = 0; i < 660; i++) {
+            resultString.append(partialString);
+        }
+        return resultString.toString();
+    }
+
     private void removeNonSystemUsers() {
         for (UserInfo user : mUms.getUsers(true)) {
             if (!user.getUserHandle().isSystem()) {
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 8ab45070a0172e0b0095d9cb520f2b8298502223..18a4f00689096cd0b3a35872df8a1d740dd291c0 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -16,7 +16,7 @@ android_test {
         "coretests-aidl",
         "platformprotosnano",
         "junit",
-        "truth-prebuilt",
+        "truth",
         "androidx.test.runner",
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 71f7f577d038fda55789f231628eddbb1379c9a7..2ece8c74420c95aa4dba23c4e02522836c05e62e 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -61,7 +61,7 @@ android_test {
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "ShortcutManagerTestUtils",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "androidx.test.uiautomator_uiautomator",
         "platformprotosnano",
@@ -72,7 +72,7 @@ android_test {
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "junit-params",
         "ActivityContext",
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
index 9fdbdda38c75deaff17418bbc1f7e490fbf987b2..70527ce2ad328141e747f15e16ba373df219f2f8 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
@@ -228,6 +228,7 @@ public class AnrTimerTest {
         TestHandler mTestHandler;
 
         TestInjector(int skip, boolean immediate) {
+            super(mHandler);
             mTracker = new TestTracker(skip);
             mImmediate = immediate;
         }
@@ -249,9 +250,16 @@ public class AnrTimerTest {
             return mTestHandler;
         }
 
+        @Override
         AnrTimer.CpuTracker getTracker() {
             return mTracker;
         }
+
+        /** For test purposes, always enable the feature. */
+        @Override
+        boolean getFeatureEnabled() {
+            return true;
+        }
     }
 
     // Tests
@@ -261,7 +269,6 @@ public class AnrTimerTest {
     // 4. Start a couple of timers.  Verify max active timers.  Discard one and verify the active
     //    count drops by 1.  Accept one and verify the active count drops by 1.
 
-
     @Test
     public void testSimpleTimeout() throws Exception {
         // Create an immediate TestHandler.
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 1d37f9da8d7a633894eddf994f71a87880d52ec9..d1f4961ab7e53f22ca43bcf0b8f9a23bfe1a4667 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -39,7 +39,7 @@ android_test {
         "hamcrest-library",
         "servicestests-utils",
         "testables",
-        "truth-prebuilt",
+        "truth",
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
index 312057ee922d607d83f5a6534151e95d5c65d295..348d1bfd44dfcca53addc641ebcd95d27349e40d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
@@ -44,6 +44,12 @@ import org.mockito.Captor;
 import org.mockito.Mock;
 
 import java.lang.reflect.Field;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
 
 @RunWith(AndroidTestingRunner.class)
 public class NotificationBitmapJobServiceTest extends UiServiceTestCase {
@@ -103,17 +109,39 @@ public class NotificationBitmapJobServiceTest extends UiServiceTestCase {
 
     @Test
     public void testGetTimeUntilRemoval_beforeToday2am_returnTimeUntilToday2am() {
-        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 1,
-                /* today2AM= */ 2, /* tomorrow2AM= */ 26);
+        ZoneId zoneId = ZoneId.systemDefault();
+        ZonedDateTime now = Instant.now().atZone(zoneId);
+        LocalDate today = now.toLocalDate();
 
-        assertThat(timeUntilRemoval).isEqualTo(1);
+        LocalTime oneAM = LocalTime.of(/* hour= */ 1, /* minute= */ 0);
+        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0);
+
+        ZonedDateTime today1AM = ZonedDateTime.of(today, oneAM, zoneId);
+        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId);
+        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);
+
+        final long msUntilRemoval = mJobService.getTimeUntilRemoval(
+                /* now= */ today1AM, today2AM, tomorrow2AM);
+
+        assertThat(msUntilRemoval).isEqualTo(Duration.ofHours(1).toMillis());
     }
 
     @Test
     public void testGetTimeUntilRemoval_afterToday2am_returnTimeUntilTomorrow2am() {
-        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 3,
-                /* today2AM= */ 2, /* tomorrow2AM= */ 26);
+        ZoneId zoneId = ZoneId.systemDefault();
+        ZonedDateTime now = Instant.now().atZone(zoneId);
+        LocalDate today = now.toLocalDate();
+
+        LocalTime threeAM = LocalTime.of(/* hour= */ 3, /* minute= */ 0);
+        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0);
+
+        ZonedDateTime today3AM = ZonedDateTime.of(today, threeAM, zoneId);
+        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId);
+        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);
+
+        final long msUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ today3AM,
+                today2AM, tomorrow2AM);
 
-        assertThat(timeUntilRemoval).isEqualTo(23);
+        assertThat(msUntilRemoval).isEqualTo(Duration.ofHours(23).toMillis());
     }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
index d758e71c62a208c4073666fa32c9f464667b5654..3499a12f5954322140076abb6f414457e1165183 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
@@ -71,10 +71,10 @@ public class NotificationHistoryJobServiceTest extends UiServiceTestCase {
     @Before
     public void setUp() throws Exception {
         mJobService = new NotificationHistoryJobService();
+        mJobService.attachBaseContext(mContext);
+        mJobService.onCreate();
+        mJobService.onBind(/* intent= */ null);  // Create JobServiceEngine within JobService.
 
-        final Field field = JobService.class.getDeclaredField("mEngine");
-        field.setAccessible(true);
-        field.set(mJobService, mock(JobServiceEngine.class));
         mContext.addMockSystemService(JobScheduler.class, mMockJobScheduler);
 
         // add NotificationManagerInternal to LocalServices
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 c98d2359b2f935185ba4c4b2552a5d7d9b52cd02..91129a14ecab32dd0760f796807008f3436ebfeb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -91,7 +91,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
-import static com.android.server.notification.NotificationManagerService.BITMAP_EXPIRATION_TIME_MS;
+import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
@@ -11381,7 +11381,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
 
         long timePostedMs = System.currentTimeMillis();
         if (isExpired) {
-            timePostedMs -= BITMAP_EXPIRATION_TIME_MS;
+            timePostedMs -= BITMAP_DURATION.toMillis();
         }
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
                 notification, UserHandle.getUserHandleForUid(mUid), null, timePostedMs);
diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp
index e704ebf32270feb7bff5dbce96fb18f64b322bda..744cb63f72b3d924f6b4c823599c7210d178e2ec 100644
--- a/services/tests/voiceinteractiontests/Android.bp
+++ b/services/tests/voiceinteractiontests/Android.bp
@@ -43,7 +43,7 @@ android_test {
         "services.soundtrigger",
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index c2812a14a3eb3c5cf434edf4afd908567b259bcb..af39b2f027eecdfd2de9bff6df1c5262ced56643 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -57,12 +57,14 @@ android_test {
         "platform-test-annotations",
         "servicestests-utils",
         "testng",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "hamcrest-library",
         "platform-compat-test-rules",
         "CtsSurfaceValidatorLib",
         "service-sdksandbox.impl",
+        "com.android.window.flags.window-aconfig-java",
+        "flag-junit",
     ],
 
     libs: [
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 42e3383987d61a775371da0afe0cbf121ddc8cd8..762e23c8e2883e9c98a64aaea3c6a02274568cd9 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -47,6 +47,8 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/>
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+    <uses-permission android:name="android.permission.MONITOR_INPUT"/>
 
     <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
     <application android:debuggable="true"
@@ -104,6 +106,11 @@
             android:showWhenLocked="true"
             android:turnScreenOn="true" />
 
+        <activity android:name="android.app.Activity"
+            android:exported="true"
+            android:showWhenLocked="true"
+            android:turnScreenOn="true" />
+
         <activity
             android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
             android:exported="true">
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 3bc6450ae5910eaf2e13d76e845c2dfc16afd63f..c241033c69d3accf018fe750e45ba71b8db951ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -549,10 +549,12 @@ public class RootWindowContainerTests extends WindowTestsBase {
 
         // Let's pretend that the app has crashed.
         firstActivity.app.setThread(null);
-        mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
+        final Task finishedTask = mRootWindowContainer.finishTopCrashedActivities(
+                firstActivity.app, "test");
 
         // Verify that the root task was removed.
         assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount());
+        assertEquals(rootTask, finishedTask);
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac498397eb390b2b81f33619ed3a784b01e5c7ea
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 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.server.wm;
+
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.server.wm.BuildUtils;
+import android.server.wm.CtsWindowInfoUtils;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.window.flags.Flags;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+public class TrustedOverlayTests {
+    private static final String TAG = "TrustedOverlayTests";
+    private static final long TIMEOUT_S = 5L * BuildUtils.HW_TIMEOUT_MULTIPLIER;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Rule
+    public TestName mName = new TestName();
+
+    @Rule
+    public final ActivityScenarioRule<Activity> mActivityRule = new ActivityScenarioRule<>(
+            Activity.class);
+
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivityRule.getScenario().onActivity(activity -> {
+            mActivity = activity;
+        });
+    }
+
+    @RequiresFlagsDisabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY)
+    @Test
+    public void setTrustedOverlayInputWindow() throws InterruptedException {
+        testTrustedOverlayChildHelper(false);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY)
+    public void setTrustedOverlayChildLayer() throws InterruptedException {
+        testTrustedOverlayChildHelper(true);
+    }
+
+    /**
+     * b/300659960 where setting spy window and trusted overlay were not happening in the same
+     * transaction causing the system to crash. This ensures there are no synchronization issues
+     * setting both spy window and trusted overlay.
+     */
+    @Test
+    public void setSpyWindowDoesntCrash() throws InterruptedException {
+        IBinder[] tokens = new IBinder[1];
+        CountDownLatch hostTokenReady = new CountDownLatch(1);
+        mInstrumentation.runOnMainSync(() -> {
+            WindowManager.LayoutParams params = mActivity.getWindow().getAttributes();
+            params.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+            params.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
+            mActivity.getWindow().setAttributes(params);
+
+            View rootView = mActivity.getWindow().getDecorView();
+            if (rootView.isAttachedToWindow()) {
+                tokens[0] = rootView.getWindowToken();
+                hostTokenReady.countDown();
+            } else {
+                rootView.getViewTreeObserver().addOnWindowAttachListener(
+                        new ViewTreeObserver.OnWindowAttachListener() {
+                            @Override
+                            public void onWindowAttached() {
+                                tokens[0] = rootView.getWindowToken();
+                                hostTokenReady.countDown();
+                            }
+
+                            @Override
+                            public void onWindowDetached() {
+                            }
+                        });
+            }
+        });
+
+        assertTrue("Failed to wait for host to get added",
+                hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS));
+
+        boolean[] foundTrusted = new boolean[1];
+        CtsWindowInfoUtils.waitForWindowInfos(
+                windowInfos -> {
+                    for (var windowInfo : windowInfos) {
+                        if (windowInfo.windowToken == tokens[0] && windowInfo.isTrustedOverlay) {
+                            foundTrusted[0] = true;
+                            return true;
+                        }
+                    }
+                    return false;
+                }, TIMEOUT_S, TimeUnit.SECONDS);
+
+        if (!foundTrusted[0]) {
+            CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName());
+        }
+
+        assertTrue("Failed to find window or was not marked trusted", foundTrusted[0]);
+    }
+
+    private void testTrustedOverlayChildHelper(boolean expectedTrustedChild)
+            throws InterruptedException {
+        IBinder[] tokens = new IBinder[2];
+        CountDownLatch hostTokenReady = new CountDownLatch(1);
+        mInstrumentation.runOnMainSync(() -> {
+            mActivity.getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY);
+            View rootView = mActivity.getWindow().getDecorView();
+            if (rootView.isAttachedToWindow()) {
+                tokens[0] = rootView.getWindowToken();
+                hostTokenReady.countDown();
+            } else {
+                rootView.getViewTreeObserver().addOnWindowAttachListener(
+                        new ViewTreeObserver.OnWindowAttachListener() {
+                            @Override
+                            public void onWindowAttached() {
+                                tokens[0] = rootView.getWindowToken();
+                                hostTokenReady.countDown();
+                            }
+
+                            @Override
+                            public void onWindowDetached() {
+                            }
+                        });
+            }
+        });
+
+        assertTrue("Failed to wait for host to get added",
+                hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS));
+
+        mInstrumentation.runOnMainSync(() -> {
+            WindowManager wm = mActivity.getSystemService(WindowManager.class);
+
+            View childView = new View(mActivity) {
+                @Override
+                protected void onAttachedToWindow() {
+                    super.onAttachedToWindow();
+                    tokens[1] = getWindowToken();
+                }
+            };
+            WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+            params.token = tokens[0];
+            params.type = TYPE_APPLICATION_PANEL;
+            wm.addView(childView, params);
+        });
+
+        boolean[] foundTrusted = new boolean[2];
+
+        CtsWindowInfoUtils.waitForWindowInfos(
+                windowInfos -> {
+                    for (var windowInfo : windowInfos) {
+                        if (windowInfo.windowToken == tokens[0]
+                                && windowInfo.isTrustedOverlay) {
+                            foundTrusted[0] = true;
+                        } else if (windowInfo.windowToken == tokens[1]
+                                && windowInfo.isTrustedOverlay) {
+                            foundTrusted[1] = true;
+                        }
+                    }
+                    return foundTrusted[0] && foundTrusted[1];
+                }, TIMEOUT_S, TimeUnit.SECONDS);
+
+        if (!foundTrusted[0] || !foundTrusted[1]) {
+            CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName());
+        }
+
+        assertTrue("Failed to find parent window or was not marked trusted", foundTrusted[0]);
+        assertEquals("Failed to find child window or was not marked trusted", expectedTrustedChild,
+                foundTrusted[1]);
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsHandlerThread.java b/services/usage/java/com/android/server/usage/UsageStatsHandlerThread.java
deleted file mode 100644
index 6801c940253890583a0c5d74242540ebd86972c2..0000000000000000000000000000000000000000
--- a/services/usage/java/com/android/server/usage/UsageStatsHandlerThread.java
+++ /dev/null
@@ -1,80 +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.server.usage;
-
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Process;
-import android.os.Trace;
-
-import java.util.concurrent.Executor;
-
-/**
- * Shared singleton default priority thread for usage stats message handling.
- *
- * @see com.android.internal.os.BackgroundThread
- */
-public final class UsageStatsHandlerThread extends HandlerThread {
-    private static final long SLOW_DISPATCH_THRESHOLD_MS = 10_000;
-    private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000;
-    private static UsageStatsHandlerThread sInstance;
-    private static Handler sHandler;
-    private static Executor sHandlerExecutor;
-
-    private UsageStatsHandlerThread() {
-        super("usagestats.default", Process.THREAD_PRIORITY_DEFAULT);
-    }
-
-    private static void ensureThreadLocked() {
-        if (sInstance == null) {
-            sInstance = new UsageStatsHandlerThread();
-            sInstance.start();
-            final Looper looper = sInstance.getLooper();
-            looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
-            looper.setSlowLogThresholdMs(
-                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
-            sHandler = new Handler(sInstance.getLooper());
-            sHandlerExecutor = new HandlerExecutor(sHandler);
-        }
-    }
-
-    /** Returns the UsageStatsHandlerThread singleton */
-    public static UsageStatsHandlerThread get() {
-        synchronized (UsageStatsHandlerThread.class) {
-            ensureThreadLocked();
-            return sInstance;
-        }
-    }
-
-    /** Returns the singleton handler for UsageStatsHandlerThread */
-    public static Handler getHandler() {
-        synchronized (UsageStatsHandlerThread.class) {
-            ensureThreadLocked();
-            return sHandler;
-        }
-    }
-
-    /** Returns the singleton handler executor for UsageStatsHandlerThread */
-    public static Executor getExecutor() {
-        synchronized (UsageStatsHandlerThread.class) {
-            ensureThreadLocked();
-            return sHandlerExecutor;
-        }
-    }
-}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 9956faaa2eb16dba34b2a6d09b34bc268c91488f..6cebe0af7a3587e13cd4d10266a8eb69bd100423 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -106,7 +106,6 @@ import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
@@ -202,8 +201,7 @@ public class UsageStatsService extends SystemService implements
     static final int MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED = 9;
 
     private final Object mLock = new Object();
-    private Handler mHandler;
-    private Handler mIoHandler;
+    Handler mHandler;
     AppOpsManager mAppOps;
     UserManager mUserManager;
     PackageManager mPackageManager;
@@ -235,7 +233,7 @@ public class UsageStatsService extends SystemService implements
     private final SparseArray<LinkedList<Event>> mReportedEvents = new SparseArray<>();
     final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
     final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
-    @GuardedBy("mLaunchTimeAlarmQueues") // Don't hold the main lock
+    @GuardedBy("mLock")
     private final SparseArray<LaunchTimeAlarmQueue> mLaunchTimeAlarmQueues = new SparseArray<>();
     @GuardedBy("mUsageEventListeners") // Don't hold the main lock when calling out
     private final ArraySet<UsageStatsManagerInternal.UsageEventListener> mUsageEventListeners =
@@ -281,38 +279,6 @@ public class UsageStatsService extends SystemService implements
         }
     }
 
-    private final Handler.Callback mIoHandlerCallback = (msg) -> {
-        switch (msg.what) {
-            case MSG_UID_STATE_CHANGED: {
-                final int uid = msg.arg1;
-                final int procState = msg.arg2;
-
-                final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1;
-                synchronized (mUidToKernelCounter) {
-                    final int oldCounter = mUidToKernelCounter.get(uid, 0);
-                    if (newCounter != oldCounter) {
-                        mUidToKernelCounter.put(uid, newCounter);
-                        try {
-                            FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter);
-                        } catch (IOException e) {
-                            Slog.w(TAG, "Failed to update counter set: " + e);
-                        }
-                    }
-                }
-                return true;
-            }
-            case MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK: {
-                final int userId = msg.arg1;
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
-                        "usageStatsHandleEstimatedLaunchTimesOnUser(" + userId + ")");
-                handleEstimatedLaunchTimesOnUserUnlock(userId);
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                return true;
-            }
-        }
-        return false;
-    };
-
     private final Injector mInjector;
 
     public UsageStatsService(Context context) {
@@ -332,9 +298,7 @@ public class UsageStatsService extends SystemService implements
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mPackageManager = getContext().getPackageManager();
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
-
-        mHandler = new H(UsageStatsHandlerThread.get().getLooper());
-        mIoHandler = new Handler(IoThread.get().getLooper(), mIoHandlerCallback);
+        mHandler = new H(BackgroundThread.get().getLooper());
 
         mAppStandby = mInjector.getAppStandbyController(getContext());
         mResponseStatsTracker = new BroadcastResponseStatsTracker(mAppStandby, getContext());
@@ -460,9 +424,6 @@ public class UsageStatsService extends SystemService implements
             }
             mUserUnlockedStates.remove(userId);
             mUserState.put(userId, null); // release the service (mainly for GC)
-        }
-
-        synchronized (mLaunchTimeAlarmQueues) {
             LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
             if (alarmQueue != null) {
                 alarmQueue.removeAllAlarms();
@@ -518,12 +479,10 @@ public class UsageStatsService extends SystemService implements
             }
             reportEvent(unlockEvent, userId);
 
-            mIoHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK,
-                    userId, 0).sendToTarget();
+            mHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK, userId, 0).sendToTarget();
 
             // Remove all the stats stored in system DE.
             deleteRecursively(new File(Environment.getDataSystemDeDirectory(userId), "usagestats"));
-
             // Force a flush to disk for the current user to ensure important events are persisted.
             // Note: there is a very very small chance that the system crashes between deleting
             // the stats above from DE and persisting them to CE here in which case we will lose
@@ -642,7 +601,7 @@ public class UsageStatsService extends SystemService implements
     private final IUidObserver mUidObserver = new UidObserver() {
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
-            mIoHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget();
+            mHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget();
         }
 
         @Override
@@ -714,18 +673,16 @@ public class UsageStatsService extends SystemService implements
                 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED);
     }
 
-    private static void deleteRecursively(final File path) {
-        if (path.isDirectory()) {
-            final File[] files = path.listFiles();
-            if (files != null) {
-                for (File subFile : files) {
-                    deleteRecursively(subFile);
-                }
+    private static void deleteRecursively(File f) {
+        File[] files = f.listFiles();
+        if (files != null) {
+            for (File subFile : files) {
+                deleteRecursively(subFile);
             }
         }
 
-        if (path.exists() && !path.delete()) {
-            Slog.e(TAG, "Failed to delete " + path);
+        if (f.exists() && !f.delete()) {
+            Slog.e(TAG, "Failed to delete " + f);
         }
     }
 
@@ -1287,9 +1244,6 @@ public class UsageStatsService extends SystemService implements
             Slog.i(TAG, "Removing user " + userId + " and all data.");
             mUserState.remove(userId);
             mAppTimeLimit.onUserRemoved(userId);
-        }
-
-        synchronized (mLaunchTimeAlarmQueues) {
             final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
             if (alarmQueue != null) {
                 alarmQueue.removeAllAlarms();
@@ -1320,13 +1274,6 @@ public class UsageStatsService extends SystemService implements
             }
         }
 
-        synchronized (mLaunchTimeAlarmQueues) {
-            final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
-            if (alarmQueue != null) {
-                alarmQueue.removeAlarmForKey(packageName);
-            }
-        }
-
         final int tokenRemoved;
         synchronized (mLock) {
             final long timeRemoved = System.currentTimeMillis();
@@ -1335,7 +1282,10 @@ public class UsageStatsService extends SystemService implements
                 // when the user service is initialized and package manager is queried.
                 return;
             }
-
+            final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
+            if (alarmQueue != null) {
+                alarmQueue.removeAlarmForKey(packageName);
+            }
             final UserUsageStatsService userService = mUserState.get(userId);
             if (userService == null) {
                 return;
@@ -1545,63 +1495,60 @@ public class UsageStatsService extends SystemService implements
             estimatedLaunchTime = calculateEstimatedPackageLaunchTime(userId, packageName);
             mAppStandby.setEstimatedLaunchTime(packageName, userId, estimatedLaunchTime);
 
-            getOrCreateLaunchTimeAlarmQueue(userId).addAlarm(packageName,
-                    SystemClock.elapsedRealtime() + (estimatedLaunchTime - now));
-        }
-        return estimatedLaunchTime;
-    }
-
-    private LaunchTimeAlarmQueue getOrCreateLaunchTimeAlarmQueue(int userId) {
-        synchronized (mLaunchTimeAlarmQueues) {
-            LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
-            if (alarmQueue == null) {
-                alarmQueue = new LaunchTimeAlarmQueue(
-                    userId, getContext(), BackgroundThread.get().getLooper());
-                mLaunchTimeAlarmQueues.put(userId, alarmQueue);
+            synchronized (mLock) {
+                LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
+                if (alarmQueue == null) {
+                    alarmQueue = new LaunchTimeAlarmQueue(
+                            userId, getContext(), BackgroundThread.get().getLooper());
+                    mLaunchTimeAlarmQueues.put(userId, alarmQueue);
+                }
+                alarmQueue.addAlarm(packageName,
+                        SystemClock.elapsedRealtime() + (estimatedLaunchTime - now));
             }
-
-            return alarmQueue;
         }
+        return estimatedLaunchTime;
     }
 
     @CurrentTimeMillisLong
     private long calculateEstimatedPackageLaunchTime(int userId, String packageName) {
-        final long endTime = System.currentTimeMillis();
-        final long beginTime = endTime - ONE_WEEK;
-        final long unknownTime = endTime + UNKNOWN_LAUNCH_TIME_DELAY_MS;
-        final UsageEvents events = queryEarliestEventsForPackage(
-                userId, beginTime, endTime, packageName, Event.ACTIVITY_RESUMED);
-        if (events == null) {
-            if (DEBUG) {
-                Slog.d(TAG, "No events for " + userId + ":" + packageName);
-            }
-            return unknownTime;
-        }
-        final UsageEvents.Event event = new UsageEvents.Event();
-        final boolean hasMoreThan24HoursOfHistory;
-        if (events.getNextEvent(event)) {
-            hasMoreThan24HoursOfHistory = endTime - event.getTimeStamp() > ONE_DAY;
-            if (DEBUG) {
-                Slog.d(TAG, userId + ":" + packageName + " history > 24 hours="
-                        + hasMoreThan24HoursOfHistory);
-            }
-        } else {
-            if (DEBUG) {
-                Slog.d(TAG, userId + ":" + packageName + " has no events");
+        synchronized (mLock) {
+            final long endTime = System.currentTimeMillis();
+            final long beginTime = endTime - ONE_WEEK;
+            final long unknownTime = endTime + UNKNOWN_LAUNCH_TIME_DELAY_MS;
+            final UsageEvents events = queryEarliestEventsForPackage(
+                    userId, beginTime, endTime, packageName, Event.ACTIVITY_RESUMED);
+            if (events == null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "No events for " + userId + ":" + packageName);
+                }
+                return unknownTime;
             }
+            final UsageEvents.Event event = new UsageEvents.Event();
+            final boolean hasMoreThan24HoursOfHistory;
+            if (events.getNextEvent(event)) {
+                hasMoreThan24HoursOfHistory = endTime - event.getTimeStamp() > ONE_DAY;
+                if (DEBUG) {
+                    Slog.d(TAG, userId + ":" + packageName + " history > 24 hours="
+                            + hasMoreThan24HoursOfHistory);
+                }
+            } else {
+                if (DEBUG) {
+                    Slog.d(TAG, userId + ":" + packageName + " has no events");
+                }
+                return unknownTime;
+            }
+            do {
+                if (event.getEventType() == Event.ACTIVITY_RESUMED) {
+                    final long timestamp = event.getTimeStamp();
+                    final long nextLaunch =
+                            calculateNextLaunchTime(hasMoreThan24HoursOfHistory, timestamp);
+                    if (nextLaunch > endTime) {
+                        return nextLaunch;
+                    }
+                }
+            } while (events.getNextEvent(event));
             return unknownTime;
         }
-        do {
-            if (event.getEventType() == Event.ACTIVITY_RESUMED) {
-                final long timestamp = event.getTimeStamp();
-                final long nextLaunch =
-                        calculateNextLaunchTime(hasMoreThan24HoursOfHistory, timestamp);
-                if (nextLaunch > endTime) {
-                    return nextLaunch;
-                }
-            }
-        } while (events.getNextEvent(event));
-        return unknownTime;
     }
 
     @CurrentTimeMillisLong
@@ -1622,54 +1569,61 @@ public class UsageStatsService extends SystemService implements
     }
 
     private void handleEstimatedLaunchTimesOnUserUnlock(int userId) {
-        final long nowElapsed = SystemClock.elapsedRealtime();
-        final long now = System.currentTimeMillis();
-        final long beginTime = now - ONE_WEEK;
-        final UsageEvents events = queryEarliestAppEvents(
-                userId, beginTime, now, Event.ACTIVITY_RESUMED);
-        if (events == null) {
-            return;
-        }
-        final ArrayMap<String, Boolean> hasMoreThan24HoursOfHistory = new ArrayMap<>();
-        final UsageEvents.Event event = new UsageEvents.Event();
-        boolean changedTimes = false;
-        final LaunchTimeAlarmQueue alarmQueue = getOrCreateLaunchTimeAlarmQueue(userId);
-        for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent;
-                unprocessedEvent = events.getNextEvent(event)) {
-            final String packageName = event.getPackageName();
-            if (!hasMoreThan24HoursOfHistory.containsKey(packageName)) {
-                boolean hasHistory = now - event.getTimeStamp() > ONE_DAY;
-                if (DEBUG) {
-                    Slog.d(TAG,
-                            userId + ":" + packageName + " history > 24 hours=" + hasHistory);
-                }
-                hasMoreThan24HoursOfHistory.put(packageName, hasHistory);
-            }
-            if (event.getEventType() == Event.ACTIVITY_RESUMED) {
-                long estimatedLaunchTime =
-                        mAppStandby.getEstimatedLaunchTime(packageName, userId);
-                if (estimatedLaunchTime < now || estimatedLaunchTime == Long.MAX_VALUE) {
-                    //noinspection ConstantConditions
-                    estimatedLaunchTime = calculateNextLaunchTime(
-                            hasMoreThan24HoursOfHistory.get(packageName), event.getTimeStamp());
-                    mAppStandby.setEstimatedLaunchTime(
-                            packageName, userId, estimatedLaunchTime);
-                }
-                if (estimatedLaunchTime < now + ONE_WEEK) {
-                    // Before a user is unlocked, we don't know when the app will be launched,
-                    // so we give callers the UNKNOWN time. Now that we have a better estimate,
-                    // we should notify them of the change.
+        synchronized (mLock) {
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            final long now = System.currentTimeMillis();
+            final long beginTime = now - ONE_WEEK;
+            final UsageEvents events = queryEarliestAppEvents(
+                    userId, beginTime, now, Event.ACTIVITY_RESUMED);
+            if (events == null) {
+                return;
+            }
+            final ArrayMap<String, Boolean> hasMoreThan24HoursOfHistory = new ArrayMap<>();
+            final UsageEvents.Event event = new UsageEvents.Event();
+            LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
+            if (alarmQueue == null) {
+                alarmQueue = new LaunchTimeAlarmQueue(
+                        userId, getContext(), BackgroundThread.get().getLooper());
+                mLaunchTimeAlarmQueues.put(userId, alarmQueue);
+            }
+            boolean changedTimes = false;
+            for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent;
+                    unprocessedEvent = events.getNextEvent(event)) {
+                final String packageName = event.getPackageName();
+                if (!hasMoreThan24HoursOfHistory.containsKey(packageName)) {
+                    boolean hasHistory = now - event.getTimeStamp() > ONE_DAY;
                     if (DEBUG) {
-                        Slog.d(TAG, "User " + userId + " unlock resulting in"
-                                + " estimated launch time change for " + packageName);
+                        Slog.d(TAG,
+                                userId + ":" + packageName + " history > 24 hours=" + hasHistory);
                     }
-                    changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName);
+                    hasMoreThan24HoursOfHistory.put(packageName, hasHistory);
+                }
+                if (event.getEventType() == Event.ACTIVITY_RESUMED) {
+                    long estimatedLaunchTime =
+                            mAppStandby.getEstimatedLaunchTime(packageName, userId);
+                    if (estimatedLaunchTime < now || estimatedLaunchTime == Long.MAX_VALUE) {
+                        //noinspection ConstantConditions
+                        estimatedLaunchTime = calculateNextLaunchTime(
+                                hasMoreThan24HoursOfHistory.get(packageName), event.getTimeStamp());
+                        mAppStandby.setEstimatedLaunchTime(
+                                packageName, userId, estimatedLaunchTime);
+                    }
+                    if (estimatedLaunchTime < now + ONE_WEEK) {
+                        // Before a user is unlocked, we don't know when the app will be launched,
+                        // so we give callers the UNKNOWN time. Now that we have a better estimate,
+                        // we should notify them of the change.
+                        if (DEBUG) {
+                            Slog.d(TAG, "User " + userId + " unlock resulting in"
+                                    + " estimated launch time change for " + packageName);
+                        }
+                        changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName);
+                    }
+                    alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now));
                 }
-                alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now));
             }
-        }
-        if (changedTimes) {
-            mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
+            if (changedTimes) {
+                mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
+            }
         }
     }
 
@@ -2041,11 +1995,37 @@ public class UsageStatsService extends SystemService implements
                 case MSG_PACKAGE_REMOVED:
                     onPackageRemoved(msg.arg1, (String) msg.obj);
                     break;
+                case MSG_UID_STATE_CHANGED: {
+                    final int uid = msg.arg1;
+                    final int procState = msg.arg2;
+
+                    final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1;
+                    synchronized (mUidToKernelCounter) {
+                        final int oldCounter = mUidToKernelCounter.get(uid, 0);
+                        if (newCounter != oldCounter) {
+                            mUidToKernelCounter.put(uid, newCounter);
+                            try {
+                                FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter);
+                            } catch (IOException e) {
+                                Slog.w(TAG, "Failed to update counter set: " + e);
+                            }
+                        }
+                    }
+                    break;
+                }
                 case MSG_ON_START:
                     synchronized (mLock) {
                         loadGlobalComponentUsageLocked();
                     }
                     break;
+                case MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK: {
+                    final int userId = msg.arg1;
+                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+                            "usageStatsHandleEstimatedLaunchTimesOnUser(" + userId + ")");
+                    handleEstimatedLaunchTimesOnUserUnlock(userId);
+                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                }
+                break;
                 case MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED: {
                     removeMessages(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
 
diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp
index 5233a5b8654e94afe5cc859a2f857202289ea5f8..c2a70151fa13dc44ceebaf09402c306968e9c19d 100644
--- a/tests/BatteryStatsPerfTest/Android.bp
+++ b/tests/BatteryStatsPerfTest/Android.bp
@@ -27,7 +27,7 @@ android_test {
     static_libs: [
         "androidx.test.rules",
         "apct-perftests-utils",
-        "truth-prebuilt",
+        "truth",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/tests/BinaryTransparencyHostTest/Android.bp b/tests/BinaryTransparencyHostTest/Android.bp
index 615990f22e3c48c940364097baaca1922d4933e2..38cb9869f1659155a4aaf6472a376ecf84de155d 100644
--- a/tests/BinaryTransparencyHostTest/Android.bp
+++ b/tests/BinaryTransparencyHostTest/Android.bp
@@ -30,7 +30,7 @@ java_test_host {
         "compatibility-host-util",
     ],
     static_libs: [
-        "truth-prebuilt",
+        "truth",
     ],
     data: [
         ":BinaryTransparencyTestApp",
diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp
index c4faf7f4fb1150ef320447dd15dafec9c90936e4..1fb73e2c0967e96e1c551a36aa67af16d31ddea1 100644
--- a/tests/BlobStoreTestUtils/Android.bp
+++ b/tests/BlobStoreTestUtils/Android.bp
@@ -22,12 +22,12 @@ package {
 }
 
 java_library {
-  name: "BlobStoreTestUtils",
-  srcs: ["src/**/*.java"],
-  static_libs: [
-    "truth-prebuilt",
-    "androidx.test.uiautomator_uiautomator",
-    "androidx.test.ext.junit",
-  ],
-  sdk_version: "test_current",
+    name: "BlobStoreTestUtils",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "truth",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.ext.junit",
+    ],
+    sdk_version: "test_current",
 }
diff --git a/tests/ChoreographerTests/Android.bp b/tests/ChoreographerTests/Android.bp
index ca3026705c635d089d315cb54a3c363af22bc11a..5d49120ee702ae9d9e93c175b905561097a59cbd 100644
--- a/tests/ChoreographerTests/Android.bp
+++ b/tests/ChoreographerTests/Android.bp
@@ -34,7 +34,7 @@ android_test {
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "com.google.android.material_material",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         "libchoreographertests_jni",
diff --git a/tests/CtsSurfaceControlTestsStaging/Android.bp b/tests/CtsSurfaceControlTestsStaging/Android.bp
index 680952157fdcc3f5f6c5792c8e8e619678a7bdb5..96e4a9ea43006133dac2be810e95144499d07cb1 100644
--- a/tests/CtsSurfaceControlTestsStaging/Android.bp
+++ b/tests/CtsSurfaceControlTestsStaging/Android.bp
@@ -37,7 +37,7 @@ android_test {
         "compatibility-device-util-axt",
         "com.google.android.material_material",
         "SurfaceFlingerProperties",
-        "truth-prebuilt",
+        "truth",
     ],
     resource_dirs: ["src/main/res"],
     certificate: "platform",
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.bp b/tests/DynamicCodeLoggerIntegrationTests/Android.bp
index 448d46fe5e4e7eda6e6fc50739243ce01598d0c2..3f2c8083156594af689109e57eff790787d8d85f 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.bp
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.bp
@@ -47,7 +47,7 @@ android_test {
 
     static_libs: [
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
     ],
 
     compile_multilib: "both",
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index a2ae56eaeadcf4aa8079701e060c090325743525..82aa85d55e4c6ca845097257cb67777c4a7179bb 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -236,7 +236,7 @@ java_library {
     static_libs: [
         "flickerlib",
         "flickerlib-helpers",
-        "truth-prebuilt",
+        "truth",
         "app-helpers-core",
     ],
 }
@@ -255,7 +255,7 @@ java_library {
         "flickerlib",
         "flickerlib-apphelpers",
         "flickerlib-helpers",
-        "truth-prebuilt",
+        "truth",
         "app-helpers-core",
         "wm-flicker-window-extensions",
     ],
diff --git a/tests/FsVerityTest/TEST_MAPPING b/tests/FsVerityTest/TEST_MAPPING
index 39944bed3f60ca3be9373901361c8f72e5a7e3ac..7d59d77651836f8290cfdc885595c6b7194ab76a 100644
--- a/tests/FsVerityTest/TEST_MAPPING
+++ b/tests/FsVerityTest/TEST_MAPPING
@@ -1,12 +1,7 @@
 {
-  "postsubmit": [
+  "presubmit": [
     {
       "name": "FsVerityTest"
-    },
-    // nextgen test only runs during postsubmit.
-    {
-      "name": "FsVerityTest",
-      "keywords": ["nextgen"]
     }
   ]
 }
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 365e00e2b6522e2211fff0ad452ce7ef4444dbc9..f910b8b5f02a8432a5647c216598816b4f8324e1 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -35,7 +35,7 @@ android_test {
         "services.core.unboosted",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java
similarity index 58%
rename from tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java
rename to tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java
index 1b98887199e3f7bc8757346bebda2e66a07d0758..ae7fb3b29f6ce413c2a338477a72cd09d95e6885 100644
--- a/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java
+++ b/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.server.input;
+package com.android.server.input.debug;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyFloat;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -31,11 +32,12 @@ import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
-import android.view.ViewConfiguration;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.input.InputManagerService;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -48,76 +50,50 @@ import org.junit.runner.RunWith;
 public class FocusEventDebugViewTest {
 
     private FocusEventDebugView mFocusEventDebugView;
-    private FocusEventDebugView.RotaryInputValueView mRotaryInputValueView;
-    private FocusEventDebugView.RotaryInputGraphView mRotaryInputGraphView;
-    private float mScaledVerticalScrollFactor;
+    private RotaryInputValueView mRotaryInputValueView;
+    private RotaryInputGraphView mRotaryInputGraphView;
 
     @Before
     public void setUp() throws Exception {
         Context context = InstrumentationRegistry.getContext();
-        mScaledVerticalScrollFactor =
-                ViewConfiguration.get(context).getScaledVerticalScrollFactor();
         InputManagerService mockService = mock(InputManagerService.class);
         when(mockService.monitorInput(anyString(), anyInt()))
                 .thenReturn(InputChannel.openInputChannelPair("FocusEventDebugViewTest")[1]);
 
-        mRotaryInputValueView = new FocusEventDebugView.RotaryInputValueView(context);
-        mRotaryInputGraphView = new FocusEventDebugView.RotaryInputGraphView(context);
+        mRotaryInputValueView = spy(new RotaryInputValueView(context));
+        mRotaryInputGraphView = spy(new RotaryInputGraphView(context));
         mFocusEventDebugView = new FocusEventDebugView(context, mockService,
                 () -> mRotaryInputValueView, () -> mRotaryInputGraphView);
     }
 
     @Test
-    public void startsRotaryInputValueViewWithDefaultValue() {
-        assertEquals("+0.0", mRotaryInputValueView.getText());
-    }
-
-    @Test
-    public void startsRotaryInputGraphViewWithDefaultFrameCenter() {
-        assertEquals(0, mRotaryInputGraphView.getFrameCenterPosition(), 0.01);
-    }
-
-    @Test
-    public void handleRotaryInput_updatesRotaryInputValueViewWithScrollValue() {
-        mFocusEventDebugView.handleUpdateShowRotaryInput(true);
-
-        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f));
-
-        assertEquals(String.format("+%.1f", 0.5f * mScaledVerticalScrollFactor),
-                mRotaryInputValueView.getText());
-    }
-
-    @Test
-    public void handleRotaryInput_translatesRotaryInputGraphViewWithHighScrollValue() {
+    public void handleRotaryInput_sendsMotionEventWhenEnabled() {
         mFocusEventDebugView.handleUpdateShowRotaryInput(true);
 
-        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(1000f));
+        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f,  10L));
 
-        assertTrue(mRotaryInputGraphView.getFrameCenterPosition() > 0);
+        verify(mRotaryInputGraphView).addValue(0.5f, 10L);
+        verify(mRotaryInputValueView).updateValue(0.5f);
     }
 
     @Test
-    public void updateActivityStatus_setsAndRemovesColorFilter() {
-        // It should not be active initially.
-        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
+    public void handleRotaryInput_doesNotSendMotionEventWhenDisabled() {
+        mFocusEventDebugView.handleUpdateShowRotaryInput(false);
 
-        mRotaryInputValueView.updateActivityStatus(true);
-        // It should be active after rotary input.
-        assertNotNull(mRotaryInputValueView.getBackground().getColorFilter());
+        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f, 10L));
 
-        mRotaryInputValueView.updateActivityStatus(false);
-        // It should not be active after waiting for mUpdateActivityStatusCallback.
-        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
+        verify(mRotaryInputGraphView, never()).addValue(anyFloat(), anyLong());
+        verify(mRotaryInputValueView, never()).updateValue(anyFloat());
     }
 
-    private MotionEvent createRotaryMotionEvent(float scrollAxisValue) {
+    private MotionEvent createRotaryMotionEvent(float scrollAxisValue, long eventTime) {
         PointerCoords pointerCoords = new PointerCoords();
         pointerCoords.setAxisValue(MotionEvent.AXIS_SCROLL, scrollAxisValue);
         PointerProperties pointerProperties = new PointerProperties();
 
         return MotionEvent.obtain(
                 /* downTime */ 0,
-                /* eventTime */ 0,
+                /* eventTime */ eventTime,
                 /* action */ MotionEvent.ACTION_SCROLL,
                 /* pointerCount */ 1,
                 /* pointerProperties */ new PointerProperties[] {pointerProperties},
diff --git a/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java b/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..af6ece414fd162909c99b09bac7d9dbbfc034274
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 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.server.input.debug;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ * atest RotaryInputGraphViewTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RotaryInputGraphViewTest {
+
+    private RotaryInputGraphView mRotaryInputGraphView;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+
+        mRotaryInputGraphView = new RotaryInputGraphView(context);
+    }
+
+    @Test
+    public void startsWithDefaultFrameCenter() {
+        assertEquals(0, mRotaryInputGraphView.getFrameCenterPosition(), 0.01);
+    }
+
+    @Test
+    public void addValue_translatesRotaryInputGraphViewWithHighScrollValue() {
+        final float scrollAxisValue = 1000f;
+        final long eventTime = 0;
+
+        mRotaryInputGraphView.addValue(scrollAxisValue, eventTime);
+
+        assertTrue(mRotaryInputGraphView.getFrameCenterPosition() > 0);
+    }
+}
diff --git a/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java b/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5e3852dc3183d6b6f44d1998615ae0843ed468c
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 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.server.input.debug;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.view.ViewConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+/**
+ * Build/Install/Run:
+ * atest RotaryInputValueViewTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RotaryInputValueViewTest {
+
+    private final Locale mDefaultLocale = Locale.getDefault();
+
+    private RotaryInputValueView mRotaryInputValueView;
+    private float mScaledVerticalScrollFactor;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+        mScaledVerticalScrollFactor =
+                ViewConfiguration.get(context).getScaledVerticalScrollFactor();
+
+        mRotaryInputValueView = new RotaryInputValueView(context);
+    }
+
+    @Test
+    public void startsWithDefaultValue() {
+        assertEquals("+0.0", mRotaryInputValueView.getText().toString());
+    }
+
+    @Test
+    public void updateValue_updatesTextWithScrollValue() {
+        final float scrollAxisValue = 1000f;
+        final String expectedText = String.format(mDefaultLocale, "+%.1f",
+                scrollAxisValue * mScaledVerticalScrollFactor);
+
+        mRotaryInputValueView.updateValue(scrollAxisValue);
+
+        assertEquals(expectedText, mRotaryInputValueView.getText().toString());
+    }
+
+    @Test
+    public void updateActivityStatus_setsAndRemovesColorFilter() {
+        // It should not be active initially.
+        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
+
+        mRotaryInputValueView.updateActivityStatus(true);
+        // It should be active after rotary input.
+        assertNotNull(mRotaryInputValueView.getBackground().getColorFilter());
+
+        mRotaryInputValueView.updateActivityStatus(false);
+        // It should not be active after waiting for mUpdateActivityStatusCallback.
+        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
+    }
+}
diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp
index 84845c69fb27e438659e0335b0095303f5df7ab1..58ceb3f3edf4fbe7fcac7f8f9677881c73852640 100644
--- a/tests/InputMethodStressTest/Android.bp
+++ b/tests/InputMethodStressTest/Android.bp
@@ -26,7 +26,7 @@ android_test {
         "compatibility-device-util-axt",
         "platform-test-annotations",
         "platform-test-rules",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: [
         "general-tests",
diff --git a/tests/InputScreenshotTest/Android.bp b/tests/InputScreenshotTest/Android.bp
index eee486f997487272a4bb7bed27308408de4cab73..15aaa463cce7294e42e5af927a8b257a4d5dc4ab 100644
--- a/tests/InputScreenshotTest/Android.bp
+++ b/tests/InputScreenshotTest/Android.bp
@@ -29,7 +29,7 @@ android_test {
         "androidx.lifecycle_lifecycle-livedata-ktx",
         "androidx.lifecycle_lifecycle-runtime-compose",
         "androidx.navigation_navigation-compose",
-        "truth-prebuilt",
+        "truth",
         "androidx.compose.runtime_runtime",
         "androidx.test.core",
         "androidx.test.ext.junit",
@@ -47,7 +47,7 @@ android_test {
         "services.core.unboosted",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index ef45864dd93be7f39d123d955ba1d84488d407f0..ddec8fa1d70a2494e88f5621c981fe3712b88981 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -19,7 +19,7 @@ android_test {
         "junit",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "platform-test-annotations",
     ],
     java_resource_dirs: ["res"],
diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp
index 4e0b0a89d972d9849723726a211b6c44ca7e2926..909ca5972552ff8c7b9af0f4fc4c481516742afa 100644
--- a/tests/LocalizationTest/Android.bp
+++ b/tests/LocalizationTest/Android.bp
@@ -34,7 +34,7 @@ android_test {
         "androidx.test.ext.junit",
         "androidx.test.rules",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         // For mockito extended
diff --git a/tests/MidiTests/Android.bp b/tests/MidiTests/Android.bp
index 254770d21818d49fc73cce9582e3f42b2ad5c401..fcacab3fb13c032da5964fd3f0ba01ebe29a2113 100644
--- a/tests/MidiTests/Android.bp
+++ b/tests/MidiTests/Android.bp
@@ -31,7 +31,7 @@ android_test {
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
         "services.midi",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: ["libdexmakerjvmtiagent"],
     certificate: "platform",
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 1e1dc84585605175ef8b26d462bee13bd29f8225..e0e6c4c43b166f71b506be527fd1347728770189 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -32,7 +32,7 @@ android_test {
         "androidx.test.rules",
         "services.core",
         "services.net",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     jni_libs: [
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index f0f9c4bdd721f9082bafadf0b0d9ca8f6c6f2060..fd992cf415cfdf0b5d303bc2735c575a18fd14c0 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -38,7 +38,7 @@ android_test {
         "androidx.test.ext.junit",
         "mockito-target-minus-junit4",
         "testng",
-        "truth-prebuilt",
+        "truth",
         "platform-compat-test-rules",
     ],
 }
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
index 5f91f9d0e505e3c3123b103f5382d39bbccebd64..f6a41c2f44b7a2bb66426aba6bcaf4dedfd49a97 100644
--- a/tests/PlatformCompatGating/test-rules/Android.bp
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -29,7 +29,7 @@ java_library {
     static_libs: [
         "junit",
         "androidx.test.core",
-        "truth-prebuilt",
-        "core-compat-test-rules"
+        "truth",
+        "core-compat-test-rules",
     ],
 }
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
index 38313f85c31dfcde8bcedfc5c8e81c5aefb40b51..055d6258d1ac7c1c048ccba05e79cca2c8966846 100644
--- a/tests/SurfaceViewBufferTests/Android.bp
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -45,7 +45,7 @@ android_test {
         "kotlinx-coroutines-android",
         "flickerlib",
         "flickerlib-trace_processor_shell",
-        "truth-prebuilt",
+        "truth",
         "cts-wm-util",
         "CtsSurfaceValidatorLib",
     ],
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index bf12f423f145afccffba7fe9a622e267b82b65a0..d2ade34148e2793528d6fabfe0d51ded3290de9a 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -43,6 +43,6 @@ android_test {
         "kotlinx-coroutines-android",
         "flickerlib",
         "flickerlib-trace_processor_shell",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
index 81ec265c2c291bfecbb1ff96a16995160e0b9d1c..b968e5d811486cc1da01fc21b3bfeffbf1fda48f 100644
--- a/tests/TelephonyCommonTests/Android.bp
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -32,11 +32,11 @@ android_test {
     static_libs: [
         "mockito-target-extended",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
         "platform-test-annotations",
         "androidx.core_core",
         "androidx.fragment_fragment",
-        "androidx.test.ext.junit"
+        "androidx.test.ext.junit",
     ],
 
     jni_libs: ["libdexmakerjvmtiagent"],
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
index c216bced81f00ebc3fb5356d9cda50a815d45366..4e75a1d02a4128b9a3a2176049e6f7c7adc81c9d 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -28,7 +28,7 @@ android_test {
         "flag-junit",
         "mockito-target-minus-junit4",
         "servicestests-utils",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.runner",
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index 9bfcc18ee3012bec96785e4fa1315e4bde60e5d6..ddb3649a83207138c9054fdd5513a5c4992cf952 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -30,7 +30,7 @@ android_test {
         "androidx.test.uiautomator_uiautomator",
         "compatibility-device-util-axt",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: [
         "general-tests",
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index 97fbf5b320351007fce0e0e7af42f194f3910ed3..c02d8e96abb0a90200e90672a5ab6d2081a8dc6a 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -31,7 +31,7 @@ android_test {
         "androidx.test.rules",
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
         "UsbManagerTestLib",
     ],
     jni_libs: ["libdexmakerjvmtiagent"],
diff --git a/tests/UsbManagerTests/lib/Android.bp b/tests/UsbManagerTests/lib/Android.bp
index 994484cd63bf02b8feeeaea57a48572ee7100937..4e5a70fef0ca5907b38d088e2aaa4490d679f020 100644
--- a/tests/UsbManagerTests/lib/Android.bp
+++ b/tests/UsbManagerTests/lib/Android.bp
@@ -34,7 +34,7 @@ android_library {
         "services.core",
         "services.net",
         "services.usb",
-        "truth-prebuilt",
+        "truth",
         "androidx.core_core",
     ],
     libs: [
diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp
index c60c519ec4d42147853ee5bd55cbbe19a89dc6a0..92c271165ad7b974697dd85d6e4b594d45cb1c77 100644
--- a/tests/UsbTests/Android.bp
+++ b/tests/UsbTests/Android.bp
@@ -34,7 +34,7 @@ android_test {
         "services.core",
         "services.net",
         "services.usb",
-        "truth-prebuilt",
+        "truth",
         "UsbManagerTestLib",
     ],
     jni_libs: [
diff --git a/tests/componentalias/Android.bp b/tests/componentalias/Android.bp
index 01d34e4ff645c346f50c2b98d7e87817a7cc5dd9..39037f22fdcb90ea2071ee5b745ba1b2a14d29ce 100644
--- a/tests/componentalias/Android.bp
+++ b/tests/componentalias/Android.bp
@@ -25,7 +25,7 @@ java_defaults {
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.base"],
     srcs: [
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
index e7fb2debfc4ea1514566c384def3c54c1236591f..b71e5c47c70e54bb9372f193e23903c6a4d5a1f5 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
@@ -24,7 +24,7 @@ java_library_host {
     ],
     static_libs: [
         "junit",
-        "truth-prebuilt",
+        "truth",
         "mockito",
 
         // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
index 05d6a43cdb0f49bb5e245e30c5d87fe5e5e3416f..f9dc305a4e3e9f04281a74ba78fdde33359acfed 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -104,7 +104,7 @@ java_library_host {
     ],
     static_libs: [
         "junit",
-        "truth-prebuilt",
+        "truth",
 
         // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
         "platform-test-annotations",
diff --git a/tools/processors/immutability/Android.bp b/tools/processors/immutability/Android.bp
index a7d69039fcb0dbb00077158423736cfefbd3c232..ecc283b0b37ef4f89b6392305019f9ec475ba202 100644
--- a/tools/processors/immutability/Android.bp
+++ b/tools/processors/immutability/Android.bp
@@ -50,7 +50,7 @@ java_test_host {
 
     static_libs: [
         "compile-testing-prebuilt",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "kotlin-reflect",
         "ImmutabilityAnnotationProcessorHostLibrary",
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index 7059c52ddc76754f5ecd4a75e8d4c4e24395fb55..9c755b7d58c25833285ca41b93911f1ed0b408b1 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -38,7 +38,7 @@ java_test_host {
 
     static_libs: [
         "compile-testing-prebuilt",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "guava",
         "libintdef-annotation-processor",
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 7a299694741a8d76fddff2ff8a1bb5eb88060001..5a0f742372d758786910ab40eb50372a316b3720 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -40,7 +40,7 @@ android_test {
         "frameworks-base-testutils",
         "guava",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [