Merge "Add ENABLE_PIP_APP_ICON_OVERLAY experiment" into tm-qpr-dev
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 4f7f8ba..b9373be 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -567,11 +567,6 @@
     public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification";
 
     /**
-     * (boolean) Whether the clipboard overlay is enabled.
-     */
-    public static final String CLIPBOARD_OVERLAY_ENABLED = "clipboard_overlay_enabled";
-
-    /**
      * (boolean) Whether widget provider info would be saved to / loaded from system persistence
      * layer as opposed to individual manifests in respective apps.
      */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6a80d1c..b10df60 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3893,7 +3893,7 @@
          <p>Should only be requested by the System, should be required by
          TileService declarations.-->
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|recents" />
 
     <!-- Allows SystemUI to request third party controls.
          <p>Should only be requested by the System and required by
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 4b27bf2..fe296c7 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -18,7 +18,6 @@
     <bool name="kg_enable_camera_default_widget">true</bool>
     <bool name="kg_center_small_widgets_vertically">false</bool>
     <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
-    <bool name="kg_wake_on_acquire_start">false</bool>
     <bool name="action_bar_embed_tabs">true</bool>
     <bool name="split_action_bar_is_narrow">true</bool>
     <bool name="preferences_prefer_dual_pane">false</bool>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a6be07d..d4b151d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -652,6 +652,16 @@
          The default is false. -->
     <bool name="config_lidControlsSleep">false</bool>
 
+    <!-- The device states (supplied by DeviceStateManager) that should be treated as open by the
+         device fold controller. Default is empty. -->
+    <integer-array name="config_openDeviceStates">
+        <!-- Example:
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        -->
+    </integer-array>
+
     <!-- The device states (supplied by DeviceStateManager) that should be treated as folded by the
          display fold controller. Default is empty. -->
     <integer-array name="config_foldedDeviceStates">
@@ -672,6 +682,16 @@
         -->
     </integer-array>
 
+    <!-- The device states (supplied by DeviceStateManager) that should be treated as a rear display
+     state. Default is empty. -->
+    <integer-array name="config_rearDisplayDeviceStates">
+        <!-- Example:
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        -->
+    </integer-array>
+
     <!-- Indicates whether the window manager reacts to half-fold device states by overriding
      rotation. -->
     <bool name="config_windowManagerHalfFoldAutoRotateOverride">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9410e06..ba54183 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5154,6 +5154,14 @@
     <!-- Cling help message confirmation button when hiding the navigation bar entering immersive mode [CHAR LIMIT=30] -->
     <string name="immersive_cling_positive">Got it</string>
 
+    <!-- Text on a toast shown after the system rotates the screen for camera app
+         compatibility. [CHAR LIMIT=NONE] -->
+    <string name="display_rotation_camera_compat_toast_after_rotation">Rotate for a better view</string>
+
+    <!-- Text on a toast shown when a camera view is started within the app that may not be able
+         to display the camera preview correctly while in split screen. [CHAR LIMIT=NONE] -->
+    <string name="display_rotation_camera_compat_toast_in_split_screen">Exit split screen for a better view</string>
+
     <!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
     <string name="done_label">Done</string>
     <!--
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index be9f6d2..f95b9cf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2841,7 +2841,6 @@
   <java-symbol type="dimen" name="fast_scroller_minimum_touch_target" />
   <java-symbol type="array" name="config_cdma_international_roaming_indicators" />
   <java-symbol type="string" name="kg_text_message_separator" />
-  <java-symbol type="bool" name="kg_wake_on_acquire_start" />
 
   <java-symbol type="bool" name="config_use_sim_language_file" />
   <java-symbol type="bool" name="config_LTE_eri_for_network_name" />
@@ -4015,8 +4014,10 @@
   <java-symbol type="integer" name="config_maxScanTasksForHomeVisibility" />
 
   <!-- For Foldables -->
+  <java-symbol type="array" name="config_openDeviceStates" />
   <java-symbol type="array" name="config_foldedDeviceStates" />
   <java-symbol type="array" name="config_halfFoldedDeviceStates" />
+  <java-symbol type="array" name="config_rearDisplayDeviceStates" />
   <java-symbol type="bool" name="config_windowManagerHalfFoldAutoRotateOverride" />
   <java-symbol type="array" name="config_deviceStatesOnWhichToWakeUp" />
   <java-symbol type="array" name="config_deviceStatesOnWhichToSleep" />
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 798688e..8d96bb7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7687,7 +7687,8 @@
         Objects.requireNonNull(device);
         try {
             if (device.getId() == 0) {
-                throw new IllegalArgumentException("In valid device: " + device);
+                Log.w(TAG, "setCommunicationDevice: device not found: " + device);
+                return false;
             }
             return getService().setCommunicationDevice(mICallBack, device.getId());
         } catch (RemoteException e) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 2f4dd8f..408883e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1004,9 +1004,10 @@
 
 static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
     sp<IDrm> drm = android::DrmUtils::MakeDrm();
+    if (drm == NULL) return env->NewByteArray(0);
+
     std::vector<uint8_t> bv;
     drm->getSupportedSchemes(bv);
-
     jbyteArray jUuidBytes = env->NewByteArray(bv.size());
     env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
     return jUuidBytes;
diff --git a/packages/SystemUI/docs/device-entry/quickaffordance.md b/packages/SystemUI/docs/device-entry/quickaffordance.md
index ccb35fa..79d5718 100644
--- a/packages/SystemUI/docs/device-entry/quickaffordance.md
+++ b/packages/SystemUI/docs/device-entry/quickaffordance.md
@@ -52,6 +52,10 @@
 * Unselect an already-selected quick affordance from a slot
 * Unselect all already-selected quick affordances from a slot
 
+## Testing
+* Add a unit test for your implementation of `KeyguardQuickAffordanceConfig`
+* Manually verify that your implementation works in multi-user environments from both the main user and a secondary user
+
 ## Debugging
 To see the current state of the system, you can run `dumpsys`:
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 9ed3bac..70b5d73 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -105,6 +105,11 @@
         default void onDozingChanged(boolean isDozing) {}
 
         /**
+         * Callback to be notified when Dreaming changes. Dreaming is stored separately from state.
+         */
+        default void onDreamingChanged(boolean isDreaming) {}
+
+        /**
          * Callback to be notified when the doze amount changes. Useful for animations.
          * Note: this will be called for each animation frame. Please be careful to avoid
          * performance regressions.
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 2cac9c7..90851e2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -45,7 +45,7 @@
           android:id="@+id/user_switcher_header"
           android:textDirection="locale"
           android:layout_width="@dimen/bouncer_user_switcher_width"
-          android:layout_height="wrap_content" />
+          android:layout_height="match_parent" />
     </com.android.keyguard.KeyguardUserSwitcherAnchor>
 
 </LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index a1068c6..6c8db91 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -25,9 +25,6 @@
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_top_margin">12dp</dimen>
 
-    <!-- Padding for the lock icon on the keyguard -->
-    <dimen name="lock_icon_padding">16dp</dimen>
-
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">100dp</dimen>
     <dimen name="widget_label_font_size">18sp</dimen>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml b/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml
deleted file mode 100644
index 1a1fc75..0000000
--- a/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml
+++ /dev/null
@@ -1,160 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<com.android.systemui.screenshot.DraggableConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/clipboard_ui"
-    android:theme="@style/FloatingOverlay"
-    android:alpha="0"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:contentDescription="@string/clipboard_overlay_window_name">
-    <ImageView
-        android:id="@+id/actions_container_background"
-        android:visibility="gone"
-        android:layout_height="0dp"
-        android:layout_width="0dp"
-        android:elevation="4dp"
-        android:background="@drawable/action_chip_container_background"
-        android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
-        app:layout_constraintBottom_toBottomOf="@+id/actions_container"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@+id/actions_container"
-        app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
-    <HorizontalScrollView
-        android:id="@+id/actions_container"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
-        android:paddingEnd="@dimen/overlay_action_container_padding_right"
-        android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
-        android:elevation="4dp"
-        android:scrollbars="none"
-        android:layout_marginBottom="4dp"
-        app:layout_constraintHorizontal_bias="0"
-        app:layout_constraintWidth_percent="1.0"
-        app:layout_constraintWidth_max="wrap"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/preview_border"
-        app:layout_constraintEnd_toEndOf="parent">
-        <LinearLayout
-            android:id="@+id/actions"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:animateLayoutChanges="true">
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/share_chip"/>
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/remote_copy_chip"/>
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/edit_chip"/>
-        </LinearLayout>
-    </HorizontalScrollView>
-    <View
-        android:id="@+id/preview_border"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_marginStart="@dimen/overlay_offset_x"
-        android:layout_marginBottom="12dp"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        android:elevation="7dp"
-        app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
-        app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
-        android:background="@drawable/overlay_border"/>
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/clipboard_preview_end"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierMargin="@dimen/overlay_border_width"
-        app:barrierDirection="end"
-        app:constraint_referenced_ids="clipboard_preview"/>
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/clipboard_preview_top"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierDirection="top"
-        app:barrierMargin="@dimen/overlay_border_width_neg"
-        app:constraint_referenced_ids="clipboard_preview"/>
-    <FrameLayout
-        android:id="@+id/clipboard_preview"
-        android:elevation="7dp"
-        android:background="@drawable/overlay_preview_background"
-        android:clipChildren="true"
-        android:clipToOutline="true"
-        android:clipToPadding="true"
-        android:layout_width="@dimen/clipboard_preview_size"
-        android:layout_margin="@dimen/overlay_border_width"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        app:layout_constraintBottom_toBottomOf="@id/preview_border"
-        app:layout_constraintStart_toStartOf="@id/preview_border"
-        app:layout_constraintEnd_toEndOf="@id/preview_border"
-        app:layout_constraintTop_toTopOf="@id/preview_border">
-        <TextView android:id="@+id/text_preview"
-                  android:textFontWeight="500"
-                  android:padding="8dp"
-                  android:gravity="center|start"
-                  android:ellipsize="end"
-                  android:autoSizeTextType="uniform"
-                  android:autoSizeMinTextSize="@dimen/clipboard_overlay_min_font"
-                  android:autoSizeMaxTextSize="@dimen/clipboard_overlay_max_font"
-                  android:textColor="?attr/overlayButtonTextColor"
-                  android:textColorLink="?attr/overlayButtonTextColor"
-                  android:background="?androidprv:attr/colorAccentSecondary"
-                  android:layout_width="@dimen/clipboard_preview_size"
-                  android:layout_height="@dimen/clipboard_preview_size"/>
-        <ImageView
-            android:id="@+id/image_preview"
-            android:scaleType="fitCenter"
-            android:adjustViewBounds="true"
-            android:contentDescription="@string/clipboard_image_preview"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-        <TextView
-            android:id="@+id/hidden_preview"
-            android:visibility="gone"
-            android:textFontWeight="500"
-            android:padding="8dp"
-            android:gravity="center"
-            android:textSize="14sp"
-            android:textColor="?attr/overlayButtonTextColor"
-            android:background="?androidprv:attr/colorAccentSecondary"
-            android:layout_width="@dimen/clipboard_preview_size"
-            android:layout_height="@dimen/clipboard_preview_size"/>
-    </FrameLayout>
-    <FrameLayout
-        android:id="@+id/dismiss_button"
-        android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
-        android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
-        android:elevation="10dp"
-        android:visibility="gone"
-        android:alpha="0"
-        app:layout_constraintStart_toEndOf="@id/clipboard_preview"
-        app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
-        app:layout_constraintTop_toTopOf="@id/clipboard_preview"
-        app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
-        android:contentDescription="@string/clipboard_dismiss_description">
-        <ImageView
-            android:id="@+id/dismiss_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_margin="@dimen/overlay_dismiss_button_margin"
-            android:src="@drawable/overlay_cancel"/>
-    </FrameLayout>
-</com.android.systemui.screenshot.DraggableConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
index ef2247f..0cbf1db 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
@@ -114,7 +114,25 @@
 
     /** Dump region sampler */
     fun dump(pw: PrintWriter) {
-        regionSampler?.dump(pw)
+        pw.println("[RegionSampler]")
+        pw.println("regionSamplingEnabled: $regionSamplingEnabled")
+        pw.println("regionDarkness: $regionDarkness")
+        pw.println("lightForegroundColor: ${Integer.toHexString(lightForegroundColor)}")
+        pw.println("darkForegroundColor:${Integer.toHexString(darkForegroundColor)}")
+        pw.println("passed-in sampledView: $sampledView")
+        pw.println("calculated samplingBounds: $samplingBounds")
+        pw.println(
+            "sampledView width: ${sampledView?.width}, sampledView height: ${sampledView?.height}"
+        )
+        pw.println("screen width: ${displaySize.x}, screen height: ${displaySize.y}")
+        pw.println(
+            "sampledRegionWithOffset: ${convertBounds(calculateSampledRegion(sampledView!!))}"
+        )
+        pw.println(
+            "initialSampling for lockscreen: " +
+                "${wallpaperManager?.getWallpaperColors(WallpaperManager.FLAG_LOCK)}"
+        )
+        // TODO(b/265969235): add initialSampling dump for HS smartspace
     }
 
     fun calculateSampledRegion(sampledView: View): RectF {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 766266d..037a71e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -112,7 +112,8 @@
     public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25;
     // Freeform windows are showing in desktop mode
     public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26;
-
+    // Device dreaming state
+    public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -141,7 +142,8 @@
             SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
             SYSUI_STATE_IMMERSIVE_MODE,
             SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
-            SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE
+            SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
+            SYSUI_STATE_DEVICE_DREAMING
     })
     public @interface SystemUiStateFlags {}
 
@@ -179,6 +181,7 @@
         str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : "");
         str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
                 ? "freeform_active_in_desktop_mode" : "");
+        str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
         return str.toString();
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 1680b47..b1ce54e 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -28,10 +28,12 @@
 import androidx.annotation.VisibleForTesting
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Dumpable
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags.DOZING_MIGRATION_1
 import com.android.systemui.flags.Flags.REGION_SAMPLING
@@ -77,8 +79,9 @@
     @Background private val bgExecutor: Executor,
     @KeyguardSmallClockLog private val smallLogBuffer: LogBuffer?,
     @KeyguardLargeClockLog private val largeLogBuffer: LogBuffer?,
-    private val featureFlags: FeatureFlags
-) {
+    private val featureFlags: FeatureFlags,
+    private val dumpManager: DumpManager
+) : Dumpable {
     var clock: ClockController? = null
         set(value) {
             field = value
@@ -275,6 +278,7 @@
         configurationController.addCallback(configListener)
         batteryController.addCallback(batteryCallback)
         keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+        dumpManager.registerDumpable(this)
         disposableHandle = parent.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 listenForDozing(this)
@@ -300,6 +304,7 @@
         batteryController.removeCallback(batteryCallback)
         keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
         regionSampler?.stopRegionSampler()
+        dumpManager.unregisterDumpable(javaClass.simpleName)
     }
 
     private fun updateFontSizes() {
@@ -312,7 +317,7 @@
     /**
      * Dump information for debugging
      */
-    fun dump(pw: PrintWriter) {
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println(this)
         clock?.dump(pw)
         regionSampler?.dump(pw)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5fd2fab..9f07a20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -92,6 +92,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.settingslib.Utils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -999,8 +1000,10 @@
         private Drawable findUserIcon(int userId) {
             Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId);
             if (userIcon != null) {
-                return new BitmapDrawable(userIcon);
+                return CircleFramedDrawable.getInstance(mView.getContext(),
+                        userIcon);
             }
+
             return UserIcons.getDefaultUserIcon(mResources, userId, false);
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3581be4..54886c3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,7 +26,6 @@
 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT;
 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
 import static android.hardware.biometrics.BiometricConstants.LockoutMode;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
 import static android.hardware.biometrics.BiometricSourceType.FACE;
 import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -352,7 +351,6 @@
     private final Executor mBackgroundExecutor;
     private final SensorPrivacyManager mSensorPrivacyManager;
     private final ActiveUnlockConfig mActiveUnlockConfig;
-    private final PowerManager mPowerManager;
     private final IDreamManager mDreamManager;
     private final TelephonyManager mTelephonyManager;
     @Nullable
@@ -360,7 +358,6 @@
     @Nullable
     private final FaceManager mFaceManager;
     private final LockPatternUtils mLockPatternUtils;
-    private final boolean mWakeOnFingerprintAcquiredStart;
     @VisibleForTesting
     @DevicePostureController.DevicePostureInt
     protected int mConfigFaceAuthSupportedPosture;
@@ -884,11 +881,6 @@
     private void handleFingerprintAcquired(
             @BiometricFingerprintConstants.FingerprintAcquired int acquireInfo) {
         Assert.isMainThread();
-        if (mWakeOnFingerprintAcquiredStart && acquireInfo == FINGERPRINT_ACQUIRED_START) {
-            mPowerManager.wakeUp(
-                    SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_BIOMETRIC,
-                    "com.android.systemui.keyguard:FINGERPRINT_ACQUIRED_START");
-        }
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1945,6 +1937,11 @@
             }
         }
         mGoingToSleep = true;
+        // Resetting assistant visibility state as the device is going to sleep now.
+        // TaskStackChangeListener gets triggered a little late when we transition to AoD,
+        // which results in face auth running once on AoD.
+        mAssistantVisible = false;
+        mLogger.d("Started going to sleep, mGoingToSleep=true, mAssistantVisible=false");
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_GOING_TO_SLEEP);
     }
 
@@ -2050,7 +2047,6 @@
             UiEventLogger uiEventLogger,
             // This has to be a provider because SessionTracker depends on KeyguardUpdateMonitor :(
             Provider<SessionTracker> sessionTrackerProvider,
-            PowerManager powerManager,
             TrustManager trustManager,
             SubscriptionManager subscriptionManager,
             UserManager userManager,
@@ -2087,7 +2083,6 @@
         mLogger = logger;
         mUiEventLogger = uiEventLogger;
         mSessionTrackerProvider = sessionTrackerProvider;
-        mPowerManager = powerManager;
         mTrustManager = trustManager;
         mUserManager = userManager;
         mDreamManager = dreamManager;
@@ -2098,8 +2093,6 @@
         mFpm = fingerprintManager;
         mFaceManager = faceManager;
         mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
-        mWakeOnFingerprintAcquiredStart = context.getResources()
-                        .getBoolean(com.android.internal.R.bool.kg_wake_on_acquire_start);
         mFaceAcquiredInfoIgnoreList = Arrays.stream(
                 mContext.getResources().getIntArray(
                         R.array.config_face_acquire_device_entry_ignorelist))
@@ -3342,7 +3335,8 @@
     /**
      * Handle {@link #MSG_KEYGUARD_RESET}
      */
-    private void handleKeyguardReset() {
+    @VisibleForTesting
+    protected void handleKeyguardReset() {
         mLogger.d("handleKeyguardReset");
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_KEYGUARD_RESET);
@@ -3882,7 +3876,6 @@
         pw.println("  getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
         pw.println("  getUserUnlockedWithBiometric()="
                 + getUserUnlockedWithBiometric(getCurrentUser()));
-        pw.println("  mWakeOnFingerprintAcquiredStart=" + mWakeOnFingerprintAcquiredStart);
         pw.println("  SIM States:");
         for (SimData data : mSimDatas.values()) {
             pw.println("    " + data.toString());
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 1322f16..8071a5d 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -429,6 +429,7 @@
         pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState));
         pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
         pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
+        pw.println(" mDefaultPaddingPx: " + mDefaultPaddingPx);
 
         if (mView != null) {
             mView.dump(pw, args);
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 0cbf8bc..5ad21df 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -20,13 +20,13 @@
 
 import com.android.keyguard.KeyguardHostViewController;
 import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
 
 import dagger.BindsInstance;
 import dagger.Subcomponent;
 
 /**
- * Dagger Subcomponent for the {@link KeyguardBouncer}.
+ * Dagger Subcomponent for the {@link PrimaryBouncerInteractor}.
  */
 @Subcomponent(modules = {KeyguardBouncerModule.class})
 @KeyguardBouncerScope
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index ef067b8..cb7a0a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -29,7 +29,7 @@
 import com.android.systemui.R;
 import com.android.systemui.biometrics.SideFpsController;
 import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
 
 import java.util.Optional;
 
@@ -39,7 +39,7 @@
 import dagger.Provides;
 
 /**
- * Module to create and access view related to the {@link KeyguardBouncer}.
+ * Module to create and access view related to the {@link PrimaryBouncerInteractor}.
  */
 @Module
 public interface KeyguardBouncerModule {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 4c92598..696437d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -207,7 +207,8 @@
         // Saving in instance variable since to prevent GC since
         // NotificationShadeWindowController.registerCallback() only keeps weak references.
         mNotificationShadeCallback =
-                (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) ->
+                (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded,
+                            isDreaming) ->
                         registerOrUnregisterDismissNotificationShadeAction();
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 4b57d45..04a2689 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -55,11 +55,11 @@
     private val fadeDuration = 83L
     private val retractDuration = 400L
     private var alphaInDuration: Long = 0
-    private var unlockedRippleInProgress: Boolean = false
     private val dwellShader = DwellRippleShader()
     private val dwellPaint = Paint()
     private val rippleShader = RippleShader()
     private val ripplePaint = Paint()
+    private var unlockedRippleAnimator: AnimatorSet? = null
     private var fadeDwellAnimator: Animator? = null
     private var retractDwellAnimator: Animator? = null
     private var dwellPulseOutAnimator: Animator? = null
@@ -205,7 +205,7 @@
      * Plays a ripple animation that grows to the dwellRadius with distortion.
      */
     fun startDwellRipple(isDozing: Boolean) {
-        if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) {
+        if (unlockedRippleAnimator?.isRunning == true || dwellPulseOutAnimator?.isRunning == true) {
             return
         }
 
@@ -262,9 +262,7 @@
      * Ripple that bursts outwards from the position of the sensor to the edges of the screen
      */
     fun startUnlockedRipple(onAnimationEnd: Runnable?) {
-        if (unlockedRippleInProgress) {
-            return // Ignore if ripple effect is already playing
-        }
+        unlockedRippleAnimator?.cancel()
 
         val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
             interpolator = Interpolators.LINEAR_OUT_SLOW_IN
@@ -289,14 +287,13 @@
             }
         }
 
-        val animatorSet = AnimatorSet().apply {
+        unlockedRippleAnimator = AnimatorSet().apply {
             playTogether(
                 rippleAnimator,
                 alphaInAnimator
             )
             addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?) {
-                    unlockedRippleInProgress = true
                     rippleShader.rippleFill = false
                     drawRipple = true
                     visibility = VISIBLE
@@ -304,13 +301,13 @@
 
                 override fun onAnimationEnd(animation: Animator?) {
                     onAnimationEnd?.run()
-                    unlockedRippleInProgress = false
                     drawRipple = false
                     visibility = GONE
+                    unlockedRippleAnimator = null
                 }
             })
         }
-        animatorSet.start()
+        unlockedRippleAnimator?.start()
     }
 
     fun resetRippleAlpha() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 6f594d5..c799e91 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -54,12 +54,18 @@
 import com.android.systemui.Dumpable
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.util.concurrency.DelayableExecutor
 import java.io.PrintWriter
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 private const val TAG = "SideFpsController"
 
@@ -79,6 +85,9 @@
     displayManager: DisplayManager,
     @Main private val mainExecutor: DelayableExecutor,
     @Main private val handler: Handler,
+    private val alternateBouncerInteractor: AlternateBouncerInteractor,
+    @Application private val scope: CoroutineScope,
+    private val featureFlags: FeatureFlags,
     dumpManager: DumpManager
 ) : Dumpable {
     val requests: HashSet<SideFpsUiRequestSource> = HashSet()
@@ -168,9 +177,26 @@
             }
         )
         overviewProxyService.addCallback(overviewProxyListener)
+        listenForAlternateBouncerVisibility()
+
         dumpManager.registerDumpable(this)
     }
 
+    private fun listenForAlternateBouncerVisibility() {
+        alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
+        if (featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)) {
+            scope.launch {
+                alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
+                    if (isVisible) {
+                        show(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+                    } else {
+                        hide(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+                    }
+                }
+            }
+        }
+    }
+
     /** Shows the side fps overlay if not already shown. */
     fun show(request: SideFpsUiRequestSource) {
         requests.add(request)
@@ -423,4 +449,5 @@
     AUTO_SHOW,
     /** Pin, pattern or password bouncer */
     PRIMARY_BOUNCER,
+    ALTERNATE_BOUNCER
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 63a1b76..d072ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -32,7 +32,6 @@
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
 import com.android.systemui.lifecycle.repeatWhenAttached
@@ -149,21 +148,6 @@
             }
         }
 
-    private val mPrimaryBouncerExpansionCallback: PrimaryBouncerExpansionCallback =
-        object : PrimaryBouncerExpansionCallback {
-            override fun onExpansionChanged(expansion: Float) {
-                inputBouncerHiddenAmount = expansion
-                updateAlpha()
-                updatePauseAuth()
-            }
-
-            override fun onVisibilityChanged(isVisible: Boolean) {
-                updateBouncerHiddenAmount()
-                updateAlpha()
-                updatePauseAuth()
-            }
-        }
-
     private val configurationListener: ConfigurationController.ConfigurationListener =
         object : ConfigurationController.ConfigurationListener {
             override fun onUiModeChanged() {
@@ -315,14 +299,6 @@
         statusBarState = statusBarStateController.state
         qsExpansion = keyguardViewManager.qsExpansion
         keyguardViewManager.addCallback(statusBarKeyguardViewManagerCallback)
-        if (!isModernBouncerEnabled) {
-            val bouncer = keyguardViewManager.primaryBouncer
-            bouncer?.expansion?.let {
-                mPrimaryBouncerExpansionCallback.onExpansionChanged(it)
-                bouncer.addBouncerExpansionCallback(mPrimaryBouncerExpansionCallback)
-            }
-            updateBouncerHiddenAmount()
-        }
         configurationController.addCallback(configurationListener)
         shadeExpansionStateManager.addExpansionListener(shadeExpansionListener)
         updateScaleFactor()
@@ -352,11 +328,6 @@
         }
         activityLaunchAnimator.removeListener(activityLaunchAnimatorListener)
         keyguardViewManager.removeCallback(statusBarKeyguardViewManagerCallback)
-        if (!isModernBouncerEnabled) {
-            keyguardViewManager.primaryBouncer?.removeBouncerExpansionCallback(
-                mPrimaryBouncerExpansionCallback
-            )
-        }
     }
 
     override fun dump(pw: PrintWriter, args: Array<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 805a20a..1c26841 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -18,7 +18,6 @@
 
 import static android.content.ClipDescription.CLASSIFICATION_COMPLETE;
 
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN;
@@ -29,7 +28,6 @@
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.os.SystemProperties;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -37,9 +35,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.util.DeviceConfigProxy;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -59,42 +54,28 @@
             "com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY";
 
     private final Context mContext;
-    private final DeviceConfigProxy mDeviceConfig;
     private final Provider<ClipboardOverlayController> mOverlayProvider;
-    private final ClipboardOverlayControllerLegacyFactory mOverlayFactory;
     private final ClipboardToast mClipboardToast;
     private final ClipboardManager mClipboardManager;
     private final UiEventLogger mUiEventLogger;
-    private final FeatureFlags mFeatureFlags;
-    private boolean mUsingNewOverlay;
     private ClipboardOverlay mClipboardOverlay;
 
     @Inject
-    public ClipboardListener(Context context, DeviceConfigProxy deviceConfigProxy,
+    public ClipboardListener(Context context,
             Provider<ClipboardOverlayController> clipboardOverlayControllerProvider,
-            ClipboardOverlayControllerLegacyFactory overlayFactory,
             ClipboardToast clipboardToast,
             ClipboardManager clipboardManager,
-            UiEventLogger uiEventLogger,
-            FeatureFlags featureFlags) {
+            UiEventLogger uiEventLogger) {
         mContext = context;
-        mDeviceConfig = deviceConfigProxy;
         mOverlayProvider = clipboardOverlayControllerProvider;
-        mOverlayFactory = overlayFactory;
         mClipboardToast = clipboardToast;
         mClipboardManager = clipboardManager;
         mUiEventLogger = uiEventLogger;
-        mFeatureFlags = featureFlags;
-
-        mUsingNewOverlay = mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR);
     }
 
     @Override
     public void start() {
-        if (mDeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, true)) {
-            mClipboardManager.addPrimaryClipChangedListener(this);
-        }
+        mClipboardManager.addPrimaryClipChangedListener(this);
     }
 
     @Override
@@ -120,14 +101,8 @@
             return;
         }
 
-        boolean enabled = mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR);
-        if (mClipboardOverlay == null || enabled != mUsingNewOverlay) {
-            mUsingNewOverlay = enabled;
-            if (enabled) {
-                mClipboardOverlay = mOverlayProvider.get();
-            } else {
-                mClipboardOverlay = mOverlayFactory.create(mContext);
-            }
+        if (mClipboardOverlay == null) {
+            mClipboardOverlay = mOverlayProvider.get();
             mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
         } else {
             mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java
deleted file mode 100644
index 3a040829..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.clipboardoverlay;
-
-import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISSED_OTHER;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_EDIT_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHARE_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
-
-import static java.util.Objects.requireNonNull;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.annotation.MainThread;
-import android.app.ICompatCameraControlCallback;
-import android.app.RemoteAction;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Insets;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Looper;
-import android.provider.DeviceConfig;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.Size;
-import android.util.TypedValue;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.Gravity;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.InputMonitor;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.policy.PhoneWindow;
-import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.screenshot.DraggableConstraintLayout;
-import com.android.systemui.screenshot.FloatingWindowUtil;
-import com.android.systemui.screenshot.OverlayActionChip;
-import com.android.systemui.screenshot.TimeoutHandler;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * Controls state and UI for the overlay that appears when something is added to the clipboard
- */
-public class ClipboardOverlayControllerLegacy implements ClipboardListener.ClipboardOverlay {
-    private static final String TAG = "ClipboardOverlayCtrlr";
-    private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
-
-    /** Constants for screenshot/copy deconflicting */
-    public static final String SCREENSHOT_ACTION = "com.android.systemui.SCREENSHOT";
-    public static final String SELF_PERMISSION = "com.android.systemui.permission.SELF";
-    public static final String COPY_OVERLAY_ACTION = "com.android.systemui.COPY";
-
-    private static final String EXTRA_EDIT_SOURCE_CLIPBOARD = "edit_source_clipboard";
-
-    private static final int CLIPBOARD_DEFAULT_TIMEOUT_MILLIS = 6000;
-    private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
-    private static final int FONT_SEARCH_STEP_PX = 4;
-
-    private final Context mContext;
-    private final ClipboardLogger mClipboardLogger;
-    private final BroadcastDispatcher mBroadcastDispatcher;
-    private final DisplayManager mDisplayManager;
-    private final DisplayMetrics mDisplayMetrics;
-    private final WindowManager mWindowManager;
-    private final WindowManager.LayoutParams mWindowLayoutParams;
-    private final PhoneWindow mWindow;
-    private final TimeoutHandler mTimeoutHandler;
-    private final AccessibilityManager mAccessibilityManager;
-    private final TextClassifier mTextClassifier;
-
-    private final DraggableConstraintLayout mView;
-    private final View mClipboardPreview;
-    private final ImageView mImagePreview;
-    private final TextView mTextPreview;
-    private final TextView mHiddenPreview;
-    private final View mPreviewBorder;
-    private final OverlayActionChip mEditChip;
-    private final OverlayActionChip mShareChip;
-    private final OverlayActionChip mRemoteCopyChip;
-    private final View mActionContainerBackground;
-    private final View mDismissButton;
-    private final LinearLayout mActionContainer;
-    private final ArrayList<OverlayActionChip> mActionChips = new ArrayList<>();
-
-    private Runnable mOnSessionCompleteListener;
-
-    private InputMonitor mInputMonitor;
-    private InputEventReceiver mInputEventReceiver;
-
-    private BroadcastReceiver mCloseDialogsReceiver;
-    private BroadcastReceiver mScreenshotReceiver;
-
-    private boolean mBlockAttach = false;
-    private Animator mExitAnimator;
-    private Animator mEnterAnimator;
-    private final int mOrientation;
-    private boolean mKeyboardVisible;
-
-
-    public ClipboardOverlayControllerLegacy(Context context,
-            BroadcastDispatcher broadcastDispatcher,
-            BroadcastSender broadcastSender,
-            TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) {
-        mBroadcastDispatcher = broadcastDispatcher;
-        mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
-        final Context displayContext = context.createDisplayContext(getDefaultDisplay());
-        mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
-
-        mClipboardLogger = new ClipboardLogger(uiEventLogger);
-
-        mAccessibilityManager = AccessibilityManager.getInstance(mContext);
-        mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class))
-                .getTextClassifier();
-
-        mWindowManager = mContext.getSystemService(WindowManager.class);
-
-        mDisplayMetrics = new DisplayMetrics();
-        mContext.getDisplay().getRealMetrics(mDisplayMetrics);
-
-        mTimeoutHandler = timeoutHandler;
-        mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
-
-        // Setup the window that we are going to use
-        mWindowLayoutParams = FloatingWindowUtil.getFloatingWindowParams();
-        mWindowLayoutParams.setTitle("ClipboardOverlay");
-
-        mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
-        mWindow.setWindowManager(mWindowManager, null, null);
-
-        setWindowFocusable(false);
-
-        mView = (DraggableConstraintLayout)
-                LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay_legacy, null);
-        mActionContainerBackground =
-                requireNonNull(mView.findViewById(R.id.actions_container_background));
-        mActionContainer = requireNonNull(mView.findViewById(R.id.actions));
-        mClipboardPreview = requireNonNull(mView.findViewById(R.id.clipboard_preview));
-        mImagePreview = requireNonNull(mView.findViewById(R.id.image_preview));
-        mTextPreview = requireNonNull(mView.findViewById(R.id.text_preview));
-        mHiddenPreview = requireNonNull(mView.findViewById(R.id.hidden_preview));
-        mPreviewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
-        mEditChip = requireNonNull(mView.findViewById(R.id.edit_chip));
-        mShareChip = requireNonNull(mView.findViewById(R.id.share_chip));
-        mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
-        mEditChip.setAlpha(1);
-        mShareChip.setAlpha(1);
-        mRemoteCopyChip.setAlpha(1);
-        mDismissButton = requireNonNull(mView.findViewById(R.id.dismiss_button));
-
-        mShareChip.setContentDescription(mContext.getString(com.android.internal.R.string.share));
-        mView.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
-            @Override
-            public void onInteraction() {
-                mTimeoutHandler.resetTimeout();
-            }
-
-            @Override
-            public void onSwipeDismissInitiated(Animator animator) {
-                mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
-                mExitAnimator = animator;
-            }
-
-            @Override
-            public void onDismissComplete() {
-                hideImmediate();
-            }
-        });
-
-        mTextPreview.getViewTreeObserver().addOnPreDrawListener(() -> {
-            int availableHeight = mTextPreview.getHeight()
-                    - (mTextPreview.getPaddingTop() + mTextPreview.getPaddingBottom());
-            mTextPreview.setMaxLines(availableHeight / mTextPreview.getLineHeight());
-            return true;
-        });
-
-        mDismissButton.setOnClickListener(view -> {
-            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
-            animateOut();
-        });
-
-        mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
-        mRemoteCopyChip.setIcon(
-                Icon.createWithResource(mContext, R.drawable.ic_baseline_devices_24), true);
-        mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
-        mOrientation = mContext.getResources().getConfiguration().orientation;
-
-        attachWindow();
-        withWindowAttached(() -> {
-            mWindow.setContentView(mView);
-            WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
-            mKeyboardVisible = insets.isVisible(WindowInsets.Type.ime());
-            updateInsets(insets);
-            mWindow.peekDecorView().getViewTreeObserver().addOnGlobalLayoutListener(
-                    new ViewTreeObserver.OnGlobalLayoutListener() {
-                        @Override
-                        public void onGlobalLayout() {
-                            WindowInsets insets =
-                                    mWindowManager.getCurrentWindowMetrics().getWindowInsets();
-                            boolean keyboardVisible = insets.isVisible(WindowInsets.Type.ime());
-                            if (keyboardVisible != mKeyboardVisible) {
-                                mKeyboardVisible = keyboardVisible;
-                                updateInsets(insets);
-                            }
-                        }
-                    });
-            mWindow.peekDecorView().getViewRootImpl().setActivityConfigCallback(
-                    new ViewRootImpl.ActivityConfigCallback() {
-                        @Override
-                        public void onConfigurationChanged(Configuration overrideConfig,
-                                int newDisplayId) {
-                            if (mContext.getResources().getConfiguration().orientation
-                                    != mOrientation) {
-                                mClipboardLogger.logSessionComplete(
-                                        CLIPBOARD_OVERLAY_DISMISSED_OTHER);
-                                hideImmediate();
-                            }
-                        }
-
-                        @Override
-                        public void requestCompatCameraControl(
-                                boolean showControl, boolean transformationApplied,
-                                ICompatCameraControlCallback callback) {
-                            Log.w(TAG, "unexpected requestCompatCameraControl call");
-                        }
-                    });
-        });
-
-        mTimeoutHandler.setOnTimeoutRunnable(() -> {
-            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
-            animateOut();
-        });
-
-        mCloseDialogsReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                    mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
-                    animateOut();
-                }
-            }
-        };
-
-        mBroadcastDispatcher.registerReceiver(mCloseDialogsReceiver,
-                new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS));
-        mScreenshotReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (SCREENSHOT_ACTION.equals(intent.getAction())) {
-                    mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
-                    animateOut();
-                }
-            }
-        };
-
-        mBroadcastDispatcher.registerReceiver(mScreenshotReceiver,
-                new IntentFilter(SCREENSHOT_ACTION), null, null, Context.RECEIVER_EXPORTED,
-                SELF_PERMISSION);
-        monitorOutsideTouches();
-
-        Intent copyIntent = new Intent(COPY_OVERLAY_ACTION);
-        // Set package name so the system knows it's safe
-        copyIntent.setPackage(mContext.getPackageName());
-        broadcastSender.sendBroadcast(copyIntent, SELF_PERMISSION);
-    }
-
-    @Override // ClipboardListener.ClipboardOverlay
-    public void setClipData(ClipData clipData, String clipSource) {
-        if (mExitAnimator != null && mExitAnimator.isRunning()) {
-            mExitAnimator.cancel();
-        }
-        reset();
-        String accessibilityAnnouncement;
-
-        boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
-                && clipData.getDescription().getExtras()
-                .getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
-        if (clipData == null || clipData.getItemCount() == 0) {
-            showTextPreview(
-                    mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                    mTextPreview);
-            accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
-        } else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
-            ClipData.Item item = clipData.getItemAt(0);
-            if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                    CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
-                if (item.getTextLinks() != null) {
-                    AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
-                }
-            }
-            if (isSensitive) {
-                showEditableText(
-                        mContext.getResources().getString(R.string.clipboard_asterisks), true);
-            } else {
-                showEditableText(item.getText(), false);
-            }
-            showShareChip(clipData);
-            accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
-        } else if (clipData.getItemAt(0).getUri() != null) {
-            if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
-                showShareChip(clipData);
-                accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
-            } else {
-                accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
-            }
-        } else {
-            showTextPreview(
-                    mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                    mTextPreview);
-            accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
-        }
-        Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext);
-        // Only show remote copy if it's available.
-        PackageManager packageManager = mContext.getPackageManager();
-        if (packageManager.resolveActivity(
-                remoteCopyIntent, PackageManager.ResolveInfoFlags.of(0)) != null) {
-            mRemoteCopyChip.setContentDescription(
-                    mContext.getString(R.string.clipboard_send_nearby_description));
-            mRemoteCopyChip.setVisibility(View.VISIBLE);
-            mRemoteCopyChip.setOnClickListener((v) -> {
-                mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED);
-                mContext.startActivity(remoteCopyIntent);
-                animateOut();
-            });
-            mActionContainerBackground.setVisibility(View.VISIBLE);
-        } else {
-            mRemoteCopyChip.setVisibility(View.GONE);
-        }
-        withWindowAttached(() -> {
-            if (mEnterAnimator == null || !mEnterAnimator.isRunning()) {
-                mView.post(this::animateIn);
-            }
-            mView.announceForAccessibility(accessibilityAnnouncement);
-        });
-        mTimeoutHandler.resetTimeout();
-    }
-
-    @Override // ClipboardListener.ClipboardOverlay
-    public void setOnSessionCompleteListener(Runnable runnable) {
-        mOnSessionCompleteListener = runnable;
-    }
-
-    private void classifyText(ClipData.Item item, String source) {
-        ArrayList<RemoteAction> actions = new ArrayList<>();
-        for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
-            TextClassification classification = mTextClassifier.classifyText(
-                    item.getText(), link.getStart(), link.getEnd(), null);
-            actions.addAll(classification.getActions());
-        }
-        mView.post(() -> {
-            resetActionChips();
-            if (actions.size() > 0) {
-                mActionContainerBackground.setVisibility(View.VISIBLE);
-                for (RemoteAction action : actions) {
-                    Intent targetIntent = action.getActionIntent().getIntent();
-                    ComponentName component = targetIntent.getComponent();
-                    if (component != null && !TextUtils.equals(source,
-                            component.getPackageName())) {
-                        OverlayActionChip chip = constructActionChip(action);
-                        mActionContainer.addView(chip);
-                        mActionChips.add(chip);
-                        break; // only show at most one action chip
-                    }
-                }
-            }
-        });
-    }
-
-    private void showShareChip(ClipData clip) {
-        mShareChip.setVisibility(View.VISIBLE);
-        mActionContainerBackground.setVisibility(View.VISIBLE);
-        mShareChip.setOnClickListener((v) -> shareContent(clip));
-    }
-
-    private OverlayActionChip constructActionChip(RemoteAction action) {
-        OverlayActionChip chip = (OverlayActionChip) LayoutInflater.from(mContext).inflate(
-                R.layout.overlay_action_chip, mActionContainer, false);
-        chip.setText(action.getTitle());
-        chip.setContentDescription(action.getTitle());
-        chip.setIcon(action.getIcon(), false);
-        chip.setPendingIntent(action.getActionIntent(), () -> {
-            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
-            animateOut();
-        });
-        chip.setAlpha(1);
-        return chip;
-    }
-
-    private void monitorOutsideTouches() {
-        InputManager inputManager = mContext.getSystemService(InputManager.class);
-        mInputMonitor = inputManager.monitorGestureInput("clipboard overlay", 0);
-        mInputEventReceiver = new InputEventReceiver(mInputMonitor.getInputChannel(),
-                Looper.getMainLooper()) {
-            @Override
-            public void onInputEvent(InputEvent event) {
-                if (event instanceof MotionEvent) {
-                    MotionEvent motionEvent = (MotionEvent) event;
-                    if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                        Region touchRegion = new Region();
-
-                        final Rect tmpRect = new Rect();
-                        mPreviewBorder.getBoundsOnScreen(tmpRect);
-                        tmpRect.inset(
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics,
-                                        -SWIPE_PADDING_DP));
-                        touchRegion.op(tmpRect, Region.Op.UNION);
-                        mActionContainerBackground.getBoundsOnScreen(tmpRect);
-                        tmpRect.inset(
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics,
-                                        -SWIPE_PADDING_DP));
-                        touchRegion.op(tmpRect, Region.Op.UNION);
-                        mDismissButton.getBoundsOnScreen(tmpRect);
-                        touchRegion.op(tmpRect, Region.Op.UNION);
-                        if (!touchRegion.contains(
-                                (int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
-                            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
-                            animateOut();
-                        }
-                    }
-                }
-                finishInputEvent(event, true /* handled */);
-            }
-        };
-    }
-
-    private void editImage(Uri uri) {
-        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getImageEditIntent(uri, mContext));
-        animateOut();
-    }
-
-    private void editText() {
-        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getTextEditorIntent(mContext));
-        animateOut();
-    }
-
-    private void shareContent(ClipData clip) {
-        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SHARE_TAPPED);
-        mContext.startActivity(IntentCreator.getShareIntent(clip, mContext));
-        animateOut();
-    }
-
-    private void showSinglePreview(View v) {
-        mTextPreview.setVisibility(View.GONE);
-        mImagePreview.setVisibility(View.GONE);
-        mHiddenPreview.setVisibility(View.GONE);
-        v.setVisibility(View.VISIBLE);
-    }
-
-    private void showTextPreview(CharSequence text, TextView textView) {
-        showSinglePreview(textView);
-        final CharSequence truncatedText = text.subSequence(0, Math.min(500, text.length()));
-        textView.setText(truncatedText);
-        updateTextSize(truncatedText, textView);
-
-        textView.addOnLayoutChangeListener(
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                    if (right - left != oldRight - oldLeft) {
-                        updateTextSize(truncatedText, textView);
-                    }
-                });
-        mEditChip.setVisibility(View.GONE);
-    }
-
-    private void updateTextSize(CharSequence text, TextView textView) {
-        Paint paint = new Paint(textView.getPaint());
-        Resources res = textView.getResources();
-        float minFontSize = res.getDimensionPixelSize(R.dimen.clipboard_overlay_min_font);
-        float maxFontSize = res.getDimensionPixelSize(R.dimen.clipboard_overlay_max_font);
-        if (isOneWord(text) && fitsInView(text, textView, paint, minFontSize)) {
-            // If the text is a single word and would fit within the TextView at the min font size,
-            // find the biggest font size that will fit.
-            float fontSizePx = minFontSize;
-            while (fontSizePx + FONT_SEARCH_STEP_PX < maxFontSize
-                    && fitsInView(text, textView, paint, fontSizePx + FONT_SEARCH_STEP_PX)) {
-                fontSizePx += FONT_SEARCH_STEP_PX;
-            }
-            // Need to turn off autosizing, otherwise setTextSize is a no-op.
-            textView.setAutoSizeTextTypeWithDefaults(TextView.AUTO_SIZE_TEXT_TYPE_NONE);
-            // It's possible to hit the max font size and not fill the width, so centering
-            // horizontally looks better in this case.
-            textView.setGravity(Gravity.CENTER);
-            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, (int) fontSizePx);
-        } else {
-            // Otherwise just stick with autosize.
-            textView.setAutoSizeTextTypeUniformWithConfiguration((int) minFontSize,
-                    (int) maxFontSize, FONT_SEARCH_STEP_PX, TypedValue.COMPLEX_UNIT_PX);
-            textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
-        }
-    }
-
-    private static boolean fitsInView(CharSequence text, TextView textView, Paint paint,
-            float fontSizePx) {
-        paint.setTextSize(fontSizePx);
-        float size = paint.measureText(text.toString());
-        float availableWidth = textView.getWidth() - textView.getPaddingLeft()
-                - textView.getPaddingRight();
-        return size < availableWidth;
-    }
-
-    private static boolean isOneWord(CharSequence text) {
-        return text.toString().split("\\s+", 2).length == 1;
-    }
-
-    private void showEditableText(CharSequence text, boolean hidden) {
-        TextView textView = hidden ? mHiddenPreview : mTextPreview;
-        showTextPreview(text, textView);
-        View.OnClickListener listener = v -> editText();
-        setAccessibilityActionToEdit(textView);
-        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON, false)) {
-            mEditChip.setVisibility(View.VISIBLE);
-            mActionContainerBackground.setVisibility(View.VISIBLE);
-            mEditChip.setContentDescription(
-                    mContext.getString(R.string.clipboard_edit_text_description));
-            mEditChip.setOnClickListener(listener);
-        }
-        textView.setOnClickListener(listener);
-    }
-
-    private boolean tryShowEditableImage(Uri uri, boolean isSensitive) {
-        View.OnClickListener listener = v -> editImage(uri);
-        ContentResolver resolver = mContext.getContentResolver();
-        String mimeType = resolver.getType(uri);
-        boolean isEditableImage = mimeType != null && mimeType.startsWith("image");
-        if (isSensitive) {
-            mHiddenPreview.setText(mContext.getString(R.string.clipboard_text_hidden));
-            showSinglePreview(mHiddenPreview);
-            if (isEditableImage) {
-                mHiddenPreview.setOnClickListener(listener);
-                setAccessibilityActionToEdit(mHiddenPreview);
-            }
-        } else if (isEditableImage) { // if the MIMEtype is image, try to load
-            try {
-                int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
-                // The width of the view is capped, height maintains aspect ratio, so allow it to be
-                // taller if needed.
-                Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
-                showSinglePreview(mImagePreview);
-                mImagePreview.setImageBitmap(thumbnail);
-                mImagePreview.setOnClickListener(listener);
-                setAccessibilityActionToEdit(mImagePreview);
-            } catch (IOException e) {
-                Log.e(TAG, "Thumbnail loading failed", e);
-                showTextPreview(
-                        mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                        mTextPreview);
-                isEditableImage = false;
-            }
-        } else {
-            showTextPreview(
-                    mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                    mTextPreview);
-        }
-        if (isEditableImage && DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON, false)) {
-            mEditChip.setVisibility(View.VISIBLE);
-            mActionContainerBackground.setVisibility(View.VISIBLE);
-            mEditChip.setOnClickListener(listener);
-            mEditChip.setContentDescription(
-                    mContext.getString(R.string.clipboard_edit_image_description));
-        }
-        return isEditableImage;
-    }
-
-    private void setAccessibilityActionToEdit(View view) {
-        ViewCompat.replaceAccessibilityAction(view,
-                AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
-                mContext.getString(R.string.clipboard_edit), null);
-    }
-
-    private void animateIn() {
-        if (mAccessibilityManager.isEnabled()) {
-            mDismissButton.setVisibility(View.VISIBLE);
-        }
-        mEnterAnimator = getEnterAnimation();
-        mEnterAnimator.start();
-    }
-
-    private void animateOut() {
-        if (mExitAnimator != null && mExitAnimator.isRunning()) {
-            return;
-        }
-        Animator anim = getExitAnimation();
-        anim.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                super.onAnimationCancel(animation);
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (!mCancelled) {
-                    hideImmediate();
-                }
-            }
-        });
-        mExitAnimator = anim;
-        anim.start();
-    }
-
-    private Animator getEnterAnimation() {
-        TimeInterpolator linearInterpolator = new LinearInterpolator();
-        TimeInterpolator scaleInterpolator = new PathInterpolator(0, 0, 0, 1f);
-        AnimatorSet enterAnim = new AnimatorSet();
-
-        ValueAnimator rootAnim = ValueAnimator.ofFloat(0, 1);
-        rootAnim.setInterpolator(linearInterpolator);
-        rootAnim.setDuration(66);
-        rootAnim.addUpdateListener(animation -> {
-            mView.setAlpha(animation.getAnimatedFraction());
-        });
-
-        ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 1);
-        scaleAnim.setInterpolator(scaleInterpolator);
-        scaleAnim.setDuration(333);
-        scaleAnim.addUpdateListener(animation -> {
-            float previewScale = MathUtils.lerp(.9f, 1f, animation.getAnimatedFraction());
-            mClipboardPreview.setScaleX(previewScale);
-            mClipboardPreview.setScaleY(previewScale);
-            mPreviewBorder.setScaleX(previewScale);
-            mPreviewBorder.setScaleY(previewScale);
-
-            float pivotX = mClipboardPreview.getWidth() / 2f + mClipboardPreview.getX();
-            mActionContainerBackground.setPivotX(pivotX - mActionContainerBackground.getX());
-            mActionContainer.setPivotX(pivotX - ((View) mActionContainer.getParent()).getX());
-            float actionsScaleX = MathUtils.lerp(.7f, 1f, animation.getAnimatedFraction());
-            float actionsScaleY = MathUtils.lerp(.9f, 1f, animation.getAnimatedFraction());
-            mActionContainer.setScaleX(actionsScaleX);
-            mActionContainer.setScaleY(actionsScaleY);
-            mActionContainerBackground.setScaleX(actionsScaleX);
-            mActionContainerBackground.setScaleY(actionsScaleY);
-        });
-
-        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
-        alphaAnim.setInterpolator(linearInterpolator);
-        alphaAnim.setDuration(283);
-        alphaAnim.addUpdateListener(animation -> {
-            float alpha = animation.getAnimatedFraction();
-            mClipboardPreview.setAlpha(alpha);
-            mPreviewBorder.setAlpha(alpha);
-            mDismissButton.setAlpha(alpha);
-            mActionContainer.setAlpha(alpha);
-        });
-
-        mActionContainer.setAlpha(0);
-        mPreviewBorder.setAlpha(0);
-        mClipboardPreview.setAlpha(0);
-        enterAnim.play(rootAnim).with(scaleAnim);
-        enterAnim.play(alphaAnim).after(50).after(rootAnim);
-
-        enterAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                mView.setAlpha(1);
-                mTimeoutHandler.resetTimeout();
-            }
-        });
-        return enterAnim;
-    }
-
-    private Animator getExitAnimation() {
-        TimeInterpolator linearInterpolator = new LinearInterpolator();
-        TimeInterpolator scaleInterpolator = new PathInterpolator(.3f, 0, 1f, 1f);
-        AnimatorSet exitAnim = new AnimatorSet();
-
-        ValueAnimator rootAnim = ValueAnimator.ofFloat(0, 1);
-        rootAnim.setInterpolator(linearInterpolator);
-        rootAnim.setDuration(100);
-        rootAnim.addUpdateListener(anim -> mView.setAlpha(1 - anim.getAnimatedFraction()));
-
-        ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 1);
-        scaleAnim.setInterpolator(scaleInterpolator);
-        scaleAnim.setDuration(250);
-        scaleAnim.addUpdateListener(animation -> {
-            float previewScale = MathUtils.lerp(1f, .9f, animation.getAnimatedFraction());
-            mClipboardPreview.setScaleX(previewScale);
-            mClipboardPreview.setScaleY(previewScale);
-            mPreviewBorder.setScaleX(previewScale);
-            mPreviewBorder.setScaleY(previewScale);
-
-            float pivotX = mClipboardPreview.getWidth() / 2f + mClipboardPreview.getX();
-            mActionContainerBackground.setPivotX(pivotX - mActionContainerBackground.getX());
-            mActionContainer.setPivotX(pivotX - ((View) mActionContainer.getParent()).getX());
-            float actionScaleX = MathUtils.lerp(1f, .8f, animation.getAnimatedFraction());
-            float actionScaleY = MathUtils.lerp(1f, .9f, animation.getAnimatedFraction());
-            mActionContainer.setScaleX(actionScaleX);
-            mActionContainer.setScaleY(actionScaleY);
-            mActionContainerBackground.setScaleX(actionScaleX);
-            mActionContainerBackground.setScaleY(actionScaleY);
-        });
-
-        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
-        alphaAnim.setInterpolator(linearInterpolator);
-        alphaAnim.setDuration(166);
-        alphaAnim.addUpdateListener(animation -> {
-            float alpha = 1 - animation.getAnimatedFraction();
-            mClipboardPreview.setAlpha(alpha);
-            mPreviewBorder.setAlpha(alpha);
-            mDismissButton.setAlpha(alpha);
-            mActionContainer.setAlpha(alpha);
-        });
-
-        exitAnim.play(alphaAnim).with(scaleAnim);
-        exitAnim.play(rootAnim).after(150).after(alphaAnim);
-        return exitAnim;
-    }
-
-    private void hideImmediate() {
-        // Note this may be called multiple times if multiple dismissal events happen at the same
-        // time.
-        mTimeoutHandler.cancelTimeout();
-        final View decorView = mWindow.peekDecorView();
-        if (decorView != null && decorView.isAttachedToWindow()) {
-            mWindowManager.removeViewImmediate(decorView);
-        }
-        if (mCloseDialogsReceiver != null) {
-            mBroadcastDispatcher.unregisterReceiver(mCloseDialogsReceiver);
-            mCloseDialogsReceiver = null;
-        }
-        if (mScreenshotReceiver != null) {
-            mBroadcastDispatcher.unregisterReceiver(mScreenshotReceiver);
-            mScreenshotReceiver = null;
-        }
-        if (mInputEventReceiver != null) {
-            mInputEventReceiver.dispose();
-            mInputEventReceiver = null;
-        }
-        if (mInputMonitor != null) {
-            mInputMonitor.dispose();
-            mInputMonitor = null;
-        }
-        if (mOnSessionCompleteListener != null) {
-            mOnSessionCompleteListener.run();
-        }
-    }
-
-    private void resetActionChips() {
-        for (OverlayActionChip chip : mActionChips) {
-            mActionContainer.removeView(chip);
-        }
-        mActionChips.clear();
-    }
-
-    private void reset() {
-        mView.setTranslationX(0);
-        mView.setAlpha(0);
-        mActionContainerBackground.setVisibility(View.GONE);
-        mShareChip.setVisibility(View.GONE);
-        mEditChip.setVisibility(View.GONE);
-        mRemoteCopyChip.setVisibility(View.GONE);
-        resetActionChips();
-        mTimeoutHandler.cancelTimeout();
-        mClipboardLogger.reset();
-    }
-
-    @MainThread
-    private void attachWindow() {
-        View decorView = mWindow.getDecorView();
-        if (decorView.isAttachedToWindow() || mBlockAttach) {
-            return;
-        }
-        mBlockAttach = true;
-        mWindowManager.addView(decorView, mWindowLayoutParams);
-        decorView.requestApplyInsets();
-        mView.requestApplyInsets();
-        decorView.getViewTreeObserver().addOnWindowAttachListener(
-                new ViewTreeObserver.OnWindowAttachListener() {
-                    @Override
-                    public void onWindowAttached() {
-                        mBlockAttach = false;
-                    }
-
-                    @Override
-                    public void onWindowDetached() {
-                    }
-                }
-        );
-    }
-
-    private void withWindowAttached(Runnable action) {
-        View decorView = mWindow.getDecorView();
-        if (decorView.isAttachedToWindow()) {
-            action.run();
-        } else {
-            decorView.getViewTreeObserver().addOnWindowAttachListener(
-                    new ViewTreeObserver.OnWindowAttachListener() {
-                        @Override
-                        public void onWindowAttached() {
-                            mBlockAttach = false;
-                            decorView.getViewTreeObserver().removeOnWindowAttachListener(this);
-                            action.run();
-                        }
-
-                        @Override
-                        public void onWindowDetached() {
-                        }
-                    });
-        }
-    }
-
-    private void updateInsets(WindowInsets insets) {
-        int orientation = mContext.getResources().getConfiguration().orientation;
-        FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mView.getLayoutParams();
-        if (p == null) {
-            return;
-        }
-        DisplayCutout cutout = insets.getDisplayCutout();
-        Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
-        Insets imeInsets = insets.getInsets(WindowInsets.Type.ime());
-        if (cutout == null) {
-            p.setMargins(0, 0, 0, Math.max(imeInsets.bottom, navBarInsets.bottom));
-        } else {
-            Insets waterfall = cutout.getWaterfallInsets();
-            if (orientation == ORIENTATION_PORTRAIT) {
-                p.setMargins(
-                        waterfall.left,
-                        Math.max(cutout.getSafeInsetTop(), waterfall.top),
-                        waterfall.right,
-                        Math.max(imeInsets.bottom,
-                                Math.max(cutout.getSafeInsetBottom(),
-                                        Math.max(navBarInsets.bottom, waterfall.bottom))));
-            } else {
-                p.setMargins(
-                        waterfall.left,
-                        waterfall.top,
-                        waterfall.right,
-                        Math.max(imeInsets.bottom,
-                                Math.max(navBarInsets.bottom, waterfall.bottom)));
-            }
-        }
-        mView.setLayoutParams(p);
-        mView.requestLayout();
-    }
-
-    private Display getDefaultDisplay() {
-        return mDisplayManager.getDisplay(DEFAULT_DISPLAY);
-    }
-
-    /**
-     * Updates the window focusability.  If the window is already showing, then it updates the
-     * window immediately, otherwise the layout params will be applied when the window is next
-     * shown.
-     */
-    private void setWindowFocusable(boolean focusable) {
-        int flags = mWindowLayoutParams.flags;
-        if (focusable) {
-            mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        } else {
-            mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        }
-        if (mWindowLayoutParams.flags == flags) {
-            return;
-        }
-        final View decorView = mWindow.peekDecorView();
-        if (decorView != null && decorView.isAttachedToWindow()) {
-            mWindowManager.updateViewLayout(decorView, mWindowLayoutParams);
-        }
-    }
-
-    static class ClipboardLogger {
-        private final UiEventLogger mUiEventLogger;
-        private boolean mGuarded = false;
-
-        ClipboardLogger(UiEventLogger uiEventLogger) {
-            mUiEventLogger = uiEventLogger;
-        }
-
-        void logSessionComplete(@NonNull UiEventLogger.UiEventEnum event) {
-            if (!mGuarded) {
-                mGuarded = true;
-                mUiEventLogger.log(event);
-            }
-        }
-
-        void reset() {
-            mGuarded = false;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java
deleted file mode 100644
index 0d989a7..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java
+++ /dev/null
@@ -1,54 +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.clipboardoverlay;
-
-import android.content.Context;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.screenshot.TimeoutHandler;
-
-import javax.inject.Inject;
-
-/**
- * A factory that churns out ClipboardOverlayControllerLegacys on demand.
- */
-@SysUISingleton
-public class ClipboardOverlayControllerLegacyFactory {
-
-    private final UiEventLogger mUiEventLogger;
-    private final BroadcastDispatcher mBroadcastDispatcher;
-    private final BroadcastSender mBroadcastSender;
-
-    @Inject
-    public ClipboardOverlayControllerLegacyFactory(BroadcastDispatcher broadcastDispatcher,
-            BroadcastSender broadcastSender, UiEventLogger uiEventLogger) {
-        this.mBroadcastDispatcher = broadcastDispatcher;
-        this.mBroadcastSender = broadcastSender;
-        this.mUiEventLogger = uiEventLogger;
-    }
-
-    /**
-     * One new ClipboardOverlayControllerLegacy, coming right up!
-     */
-    public ClipboardOverlayControllerLegacy create(Context context) {
-        return new ClipboardOverlayControllerLegacy(context, mBroadcastDispatcher, mBroadcastSender,
-                new TimeoutHandler(context), mUiEventLogger);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 54587b2..3808e73 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -189,9 +189,9 @@
                     authorizedPanelsRepository.addAuthorizedPanels(
                             setOf(serviceInfo.componentName.packageName)
                     )
-                    animateExitAndFinish()
                     val selected = SelectedItem.PanelItem(appName, componentName)
                     controlsController.setPreferredSelection(selected)
+                    animateExitAndFinish()
                     openControlsOrigin()
                 }
                 dialog = null
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 966dbf1..9e71bef 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -25,6 +25,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
+import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
 import android.service.controls.Control
@@ -38,6 +39,7 @@
 import android.view.animation.DecelerateInterpolator
 import android.widget.AdapterView
 import android.widget.ArrayAdapter
+import android.widget.BaseAdapter
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
@@ -90,6 +92,7 @@
 class ControlsUiControllerImpl @Inject constructor (
         val controlsController: Lazy<ControlsController>,
         val context: Context,
+        private val packageManager: PackageManager,
         @Main val uiExecutor: DelayableExecutor,
         @Background val bgExecutor: DelayableExecutor,
         val controlsListingController: Lazy<ControlsListingController>,
@@ -113,6 +116,11 @@
         private const val PREF_IS_PANEL = "controls_is_panel"
 
         private const val FADE_IN_MILLIS = 200L
+
+        private const val OPEN_APP_ID = 0L
+        private const val ADD_CONTROLS_ID = 1L
+        private const val ADD_APP_ID = 2L
+        private const val EDIT_CONTROLS_ID = 3L
     }
 
     private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
@@ -140,6 +148,9 @@
         it.getTitle()
     }
 
+    private var openAppIntent: Intent? = null
+    private var overflowMenuAdapter: BaseAdapter? = null
+
     private val onSeedingComplete = Consumer<Boolean> {
         accepted ->
             if (accepted) {
@@ -216,6 +227,8 @@
         this.parent = parent
         this.onDismiss = onDismiss
         this.activityContext = activityContext
+        this.openAppIntent = null
+        this.overflowMenuAdapter = null
         hidden = false
         retainCache = false
 
@@ -306,6 +319,12 @@
         startTargetedActivity(si, ControlsEditingActivity::class.java)
     }
 
+    private fun startDefaultActivity() {
+        openAppIntent?.let {
+            startActivity(it, animateExtra = false)
+        }
+    }
+
     private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) {
         val i = Intent(activityContext, klazz)
         putIntentExtras(i, si)
@@ -329,9 +348,11 @@
         startActivity(i)
     }
 
-    private fun startActivity(intent: Intent) {
+    private fun startActivity(intent: Intent, animateExtra: Boolean = true) {
         // Force animations when transitioning from a dialog to an activity
-        intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+        if (animateExtra) {
+            intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+        }
 
         if (keyguardStateController.isShowing()) {
             activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */)
@@ -383,8 +404,31 @@
             Log.w(ControlsUiController.TAG, "Not TaskViewFactory to display panel $selectionItem")
         }
 
+        bgExecutor.execute {
+            val intent = Intent(Intent.ACTION_MAIN)
+                    .addCategory(Intent.CATEGORY_LAUNCHER)
+                    .setPackage(selectionItem.componentName.packageName)
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
+                            Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+            val intents = packageManager
+                    .queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0L))
+            intents.firstOrNull { it.activityInfo.exported }?.let { resolved ->
+                intent.setPackage(null)
+                intent.setComponent(resolved.activityInfo.componentName)
+                openAppIntent = intent
+                parent.post {
+                    // This will call show on the PopupWindow in the same thread, so make sure this
+                    // happens in the view thread.
+                    overflowMenuAdapter?.notifyDataSetChanged()
+                }
+            }
+        }
         createDropDown(panelsAndStructures, selectionItem)
-        createMenu()
+
+        val currentApps = panelsAndStructures.map { it.componentName }.toSet()
+        val allApps = controlsListingController.get()
+                .getCurrentServices().map { it.componentName }.toSet()
+        createMenu(extraApps = (allApps - currentApps).isNotEmpty())
     }
 
     private fun createPanelView(componentName: ComponentName) {
@@ -423,28 +467,41 @@
         }
     }
 
-    private fun createMenu() {
+    private fun createMenu(extraApps: Boolean) {
         val isPanel = selectedItem is SelectedItem.PanelItem
         val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
                 ?: EMPTY_STRUCTURE
         val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
-        val addControlsId = if (newFlows || isPanel) {
-            R.string.controls_menu_add_another_app
-        } else {
-            R.string.controls_menu_add
+
+        val items = buildList {
+            add(OverflowMenuAdapter.MenuItem(
+                    context.getText(R.string.controls_open_app),
+                    OPEN_APP_ID
+            ))
+            if (newFlows || isPanel) {
+                if (extraApps) {
+                    add(OverflowMenuAdapter.MenuItem(
+                            context.getText(R.string.controls_menu_add_another_app),
+                            ADD_APP_ID
+                    ))
+                }
+            } else {
+                add(OverflowMenuAdapter.MenuItem(
+                        context.getText(R.string.controls_menu_add),
+                        ADD_CONTROLS_ID
+                ))
+            }
+            if (!isPanel) {
+                add(OverflowMenuAdapter.MenuItem(
+                        context.getText(R.string.controls_menu_edit),
+                        EDIT_CONTROLS_ID
+                ))
+            }
         }
 
-        val items = if (isPanel) {
-            arrayOf(
-                    context.resources.getString(addControlsId),
-            )
-        } else {
-            arrayOf(
-                    context.resources.getString(addControlsId),
-                    context.resources.getString(R.string.controls_menu_edit)
-            )
+        val adapter = OverflowMenuAdapter(context, R.layout.controls_more_item, items) { position ->
+                getItemId(position) != OPEN_APP_ID || openAppIntent != null
         }
-        var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items)
 
         val anchor = parent.requireViewById<ImageView>(R.id.controls_more)
         anchor.setOnClickListener(object : View.OnClickListener {
@@ -462,25 +519,21 @@
                             pos: Int,
                             id: Long
                         ) {
-                            when (pos) {
-                                // 0: Add Control
-                                0 -> {
-                                    if (isPanel || newFlows) {
-                                        startProviderSelectorActivity()
-                                    } else {
-                                        startFavoritingActivity(selectedStructure)
-                                    }
-                                }
-                                // 1: Edit controls
-                                1 -> startEditingActivity(selectedStructure)
+                            when (id) {
+                                OPEN_APP_ID -> startDefaultActivity()
+                                ADD_APP_ID -> startProviderSelectorActivity()
+                                ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure)
+                                EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure)
                             }
                             dismiss()
                         }
                     })
                     show()
+                    listView?.post { listView?.requestAccessibilityFocus() }
                 }
             }
         })
+        overflowMenuAdapter = adapter
     }
 
     private fun createDropDown(items: List<SelectionItem>, selected: SelectionItem) {
@@ -542,6 +595,7 @@
                         }
                     })
                     show()
+                    listView?.post { listView?.requestAccessibilityFocus() }
                 }
             }
         })
@@ -631,7 +685,7 @@
                 .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
                 .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
                 .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
-                .commit()
+                .apply()
     }
 
     private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt
new file mode 100644
index 0000000..6b84e36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.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.controls.ui
+
+import android.content.Context
+import android.widget.ArrayAdapter
+import androidx.annotation.LayoutRes
+
+open class OverflowMenuAdapter(
+    context: Context,
+    @LayoutRes layoutId: Int,
+    itemsWithIds: List<MenuItem>,
+    private val isEnabledInternal: OverflowMenuAdapter.(Int) -> Boolean
+) : ArrayAdapter<CharSequence>(context, layoutId, itemsWithIds.map(MenuItem::text)) {
+
+    private val ids = itemsWithIds.map(MenuItem::id)
+
+    override fun getItemId(position: Int): Long {
+        return ids[position]
+    }
+
+    override fun isEnabled(position: Int): Boolean {
+        return isEnabledInternal(position)
+    }
+
+    data class MenuItem(val text: CharSequence, val id: Long)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 8e9992f..ef07e99 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.clipboardoverlay.ClipboardListener
 import com.android.systemui.dagger.qualifiers.PerUser
+import com.android.systemui.dreams.DreamMonitor
 import com.android.systemui.globalactions.GlobalActionsComponent
 import com.android.systemui.keyboard.KeyboardUI
 import com.android.systemui.keyguard.KeyguardViewMediator
@@ -286,4 +287,10 @@
     @IntoMap
     @ClassKey(StylusUsiPowerStartable::class)
     abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable
+
+    /**Inject into DreamMonitor */
+    @Binds
+    @IntoMap
+    @ClassKey(DreamMonitor::class)
+    abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
new file mode 100644
index 0000000..102f208
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
@@ -0,0 +1,58 @@
+/*
+ * 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.dreams;
+
+import android.util.Log;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback;
+import com.android.systemui.dreams.conditions.DreamCondition;
+import com.android.systemui.shared.condition.Monitor;
+
+import javax.inject.Inject;
+
+/**
+ * A {@link CoreStartable} to retain a monitor for tracking dreaming.
+ */
+public class DreamMonitor implements CoreStartable {
+    private static final String TAG = "DreamMonitor";
+
+    // We retain a reference to the monitor so it is not garbage-collected.
+    private final Monitor mConditionMonitor;
+    private final DreamCondition mDreamCondition;
+    private final DreamStatusBarStateCallback mCallback;
+
+
+    @Inject
+    public DreamMonitor(Monitor monitor, DreamCondition dreamCondition,
+            DreamStatusBarStateCallback callback) {
+        mConditionMonitor = monitor;
+        mDreamCondition = dreamCondition;
+        mCallback = callback;
+
+    }
+    @Override
+    public void start() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "started");
+        }
+
+        mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(mCallback)
+                .addCondition(mDreamCondition)
+                .build());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c882f8a..c3bd5d9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -182,6 +182,18 @@
             }
     }
 
+    /**
+     * Ends the dream content and dream overlay animations, if they're currently running.
+     * @see [AnimatorSet.end]
+     */
+    fun endAnimations() {
+        mAnimator =
+            mAnimator?.let {
+                it.end()
+                null
+            }
+    }
+
     private fun blurAnimator(
         view: View,
         fromBlurRadius: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 33c8379..4de96e3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -40,8 +40,6 @@
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
 import com.android.systemui.statusbar.BlurUtils;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
@@ -56,7 +54,6 @@
 @DreamOverlayComponent.DreamOverlayScope
 public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
     private final DreamOverlayStatusBarViewController mStatusBarViewController;
-    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final BlurUtils mBlurUtils;
     private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
     private final DreamOverlayStateController mStateController;
@@ -127,13 +124,29 @@
                 }
             };
 
+    /**
+     * If true, overlay entry animations should be skipped once.
+     *
+     * This is turned on when exiting low light and should be turned off once the entry animations
+     * are skipped once.
+     */
+    private boolean mSkipEntryAnimations;
+
+    private final DreamOverlayStateController.Callback
+            mDreamOverlayStateCallback =
+            new DreamOverlayStateController.Callback() {
+                @Override
+                public void onExitLowLight() {
+                    mSkipEntryAnimations = true;
+                }
+            };
+
     @Inject
     public DreamOverlayContainerViewController(
             DreamOverlayContainerView containerView,
             ComplicationHostViewController complicationHostViewController,
             @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
             DreamOverlayStatusBarViewController statusBarViewController,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             BlurUtils blurUtils,
             @Main Handler handler,
             @Main Resources resources,
@@ -147,7 +160,6 @@
         super(containerView);
         mDreamOverlayContentView = contentView;
         mStatusBarViewController = statusBarViewController;
-        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mBlurUtils = blurUtils;
         mDreamOverlayAnimationsController = animationsController;
         mStateController = stateController;
@@ -170,6 +182,7 @@
 
     @Override
     protected void onInit() {
+        mStateController.addCallback(mDreamOverlayStateCallback);
         mStatusBarViewController.init();
         mComplicationHostViewController.init();
         mDreamOverlayAnimationsController.init(mView);
@@ -179,25 +192,24 @@
     protected void onViewAttached() {
         mJitterStartTimeMillis = System.currentTimeMillis();
         mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
-        final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getPrimaryBouncer();
-        if (bouncer != null) {
-            bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback);
-        }
         mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback);
 
         // Start dream entry animations. Skip animations for low light clock.
         if (!mStateController.isLowLightActive()) {
             mDreamOverlayAnimationsController.startEntryAnimations();
+
+            if (mSkipEntryAnimations) {
+                // If we're transitioning from the low light dream back to the user dream, skip the
+                // overlay animations and show immediately.
+                mDreamOverlayAnimationsController.endAnimations();
+                mSkipEntryAnimations = false;
+            }
         }
     }
 
     @Override
     protected void onViewDetached() {
         mHandler.removeCallbacks(this::updateBurnInOffsets);
-        final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getPrimaryBouncer();
-        if (bouncer != null) {
-            bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback);
-        }
         mPrimaryBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback);
 
         mDreamOverlayAnimationsController.cancelAnimations();
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index ccfdd096..2c7ecb1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -83,6 +83,12 @@
          */
         default void onAvailableComplicationTypesChanged() {
         }
+
+        /**
+         * Called when the low light dream is exiting and transitioning back to the user dream.
+         */
+        default void onExitLowLight() {
+        }
     }
 
     private final Executor mExecutor;
@@ -278,6 +284,10 @@
      * @param active {@code true} if low light mode is active, {@code false} otherwise.
      */
     public void setLowLightActive(boolean active) {
+        if (isLowLightActive() && !active) {
+            // Notify that we're exiting low light only on the transition from active to not active.
+            mCallbacks.forEach(Callback::onExitLowLight);
+        }
         modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_LOW_LIGHT_ACTIVE);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java
new file mode 100644
index 0000000..c8c9470
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java
@@ -0,0 +1,46 @@
+/*
+ * 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.dreams.callbacks;
+
+import android.util.Log;
+
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+
+import javax.inject.Inject;
+
+/**
+ * A callback that informs {@link SysuiStatusBarStateController} when the dream state has changed.
+ */
+public class DreamStatusBarStateCallback implements Monitor.Callback {
+    private static final String TAG = "DreamStatusBarCallback";
+
+    private final SysuiStatusBarStateController mStateController;
+
+    @Inject
+    public DreamStatusBarStateCallback(SysuiStatusBarStateController statusBarStateController) {
+        mStateController = statusBarStateController;
+    }
+
+    @Override
+    public void onConditionsChanged(boolean allConditionsMet) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConditionChanged:" + allConditionsMet);
+        }
+
+        mStateController.setIsDreaming(allConditionsMet);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
new file mode 100644
index 0000000..2befce7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -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.dreams.conditions;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.text.TextUtils;
+
+import com.android.systemui.shared.condition.Condition;
+
+import javax.inject.Inject;
+
+/**
+ * {@link DreamCondition} provides a signal when a dream begins and ends.
+ */
+public class DreamCondition extends Condition {
+    private final Context mContext;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            processIntent(intent);
+        }
+    };
+
+    @Inject
+    public DreamCondition(Context context) {
+        mContext = context;
+    }
+
+    private void processIntent(Intent intent) {
+        // In the case of a non-existent sticky broadcast, ignore when there is no intent.
+        if (intent == null) {
+            return;
+        }
+        if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STARTED)) {
+            updateCondition(true);
+        } else if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STOPPED)) {
+            updateCondition(false);
+        } else {
+            throw new IllegalStateException("unexpected intent:" + intent);
+        }
+    }
+
+    @Override
+    protected void start() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_DREAMING_STARTED);
+        filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+        final Intent stickyIntent = mContext.registerReceiver(mReceiver, filter);
+        processIntent(stickyIntent);
+    }
+
+    @Override
+    protected void stop() {
+        mContext.unregisterReceiver(mReceiver);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
index b94d781..dc7fc28 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.broadcast.BroadcastSender
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.InitializationChecker
 import dagger.Binds
 import dagger.Module
 import dagger.multibindings.ClassKey
@@ -34,7 +35,8 @@
     private val commandRegistry: CommandRegistry,
     private val flagCommand: FlagCommand,
     private val featureFlags: FeatureFlagsDebug,
-    private val broadcastSender: BroadcastSender
+    private val broadcastSender: BroadcastSender,
+    private val initializationChecker: InitializationChecker
 ) : CoreStartable {
 
     init {
@@ -46,8 +48,11 @@
     override fun start() {
         featureFlags.init()
         commandRegistry.registerCommand(FlagCommand.FLAG_COMMAND) { flagCommand }
-        val intent = Intent(FlagManager.ACTION_SYSUI_STARTED)
-        broadcastSender.sendBroadcast(intent)
+        if (initializationChecker.initializeComponents()) {
+            // protected broadcast should only be sent for the main process
+            val intent = Intent(FlagManager.ACTION_SYSUI_STARTED)
+            broadcastSender.sendBroadcast(intent)
+        }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 883a766..47c41fe 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -198,8 +198,7 @@
 
     /** A different path for unocclusion transitions back to keyguard */
     // TODO(b/262859270): Tracking Bug
-    @JvmField
-    val UNOCCLUSION_TRANSITION = unreleasedFlag(223, "unocclusion_transition", teamfood = true)
+    @JvmField val UNOCCLUSION_TRANSITION = releasedFlag(223, "unocclusion_transition")
 
     // flag for controlling auto pin confirmation and material u shapes in bouncer
     @JvmField
@@ -535,7 +534,6 @@
         unreleasedFlag(1600, "a11y_floating_menu_fling_spring_animations")
 
     // 1700 - clipboard
-    @JvmField val CLIPBOARD_OVERLAY_REFACTOR = releasedFlag(1700, "clipboard_overlay_refactor")
     @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
 
     // 1800 - shade container
@@ -548,7 +546,7 @@
     @JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
 
     // 2000 - device controls
-    @Keep @JvmField val USE_APP_PANELS = unreleasedFlag(2000, "use_app_panels", teamfood = true)
+    @Keep @JvmField val USE_APP_PANELS = releasedFlag(2000, "use_app_panels", teamfood = true)
 
     @JvmField
     val APP_PANELS_ALL_APPS_ALLOWED =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 482138e..680c504 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -31,10 +31,12 @@
 import android.util.Log
 import com.android.systemui.SystemUIAppComponentFactoryBase
 import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.runBlocking
 
 class CustomizationProvider :
@@ -42,6 +44,7 @@
 
     @Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
     @Inject lateinit var previewManager: KeyguardRemotePreviewManager
+    @Inject @Main lateinit var mainDispatcher: CoroutineDispatcher
 
     private lateinit var contextAvailableCallback: ContextAvailableCallback
 
@@ -138,12 +141,14 @@
         selectionArgs: Array<out String>?,
         sortOrder: String?,
     ): Cursor? {
-        return when (uriMatcher.match(uri)) {
-            MATCH_CODE_ALL_AFFORDANCES -> runBlocking { queryAffordances() }
-            MATCH_CODE_ALL_SLOTS -> querySlots()
-            MATCH_CODE_ALL_SELECTIONS -> runBlocking { querySelections() }
-            MATCH_CODE_ALL_FLAGS -> queryFlags()
-            else -> null
+        return runBlocking(mainDispatcher) {
+            when (uriMatcher.match(uri)) {
+                MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
+                MATCH_CODE_ALL_SLOTS -> querySlots()
+                MATCH_CODE_ALL_SELECTIONS -> querySelections()
+                MATCH_CODE_ALL_FLAGS -> queryFlags()
+                else -> null
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index f6e6d6b..5a9f775 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -19,6 +19,7 @@
 
 import android.app.StatusBarManager
 import android.content.Context
+import android.content.pm.PackageManager
 import com.android.systemui.R
 import com.android.systemui.animation.Expandable
 import com.android.systemui.camera.CameraGestureHelper
@@ -26,7 +27,6 @@
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.statusbar.StatusBarState
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
@@ -37,6 +37,7 @@
 @Inject
 constructor(
     @Application private val context: Context,
+    private val packageManager: PackageManager,
     private val cameraGestureHelper: Lazy<CameraGestureHelper>,
 ) : KeyguardQuickAffordanceConfig {
 
@@ -79,6 +80,6 @@
     }
 
     private fun isLaunchable(): Boolean {
-        return cameraGestureHelper.get().canCameraGestureBeLaunched(StatusBarState.KEYGUARD)
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 08edbc6..b3a9cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -22,14 +22,18 @@
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates state about device entry fingerprint auth mechanism. */
 interface DeviceEntryFingerprintAuthRepository {
     /** Whether the device entry fingerprint auth is locked out. */
-    val isLockedOut: Flow<Boolean>
+    val isLockedOut: StateFlow<Boolean>
 }
 
 /**
@@ -44,29 +48,34 @@
 @Inject
 constructor(
     val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    @Application scope: CoroutineScope,
 ) : DeviceEntryFingerprintAuthRepository {
 
-    override val isLockedOut: Flow<Boolean> = conflatedCallbackFlow {
-        val sendLockoutUpdate =
-            fun() {
-                trySendWithFailureLogging(
-                    keyguardUpdateMonitor.isFingerprintLockedOut,
-                    TAG,
-                    "onLockedOutStateChanged"
-                )
-            }
-        val callback =
-            object : KeyguardUpdateMonitorCallback() {
-                override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType?) {
-                    if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
-                        sendLockoutUpdate()
+    override val isLockedOut: StateFlow<Boolean> =
+        conflatedCallbackFlow {
+                val sendLockoutUpdate =
+                    fun() {
+                        trySendWithFailureLogging(
+                            keyguardUpdateMonitor.isFingerprintLockedOut,
+                            TAG,
+                            "onLockedOutStateChanged"
+                        )
                     }
-                }
+                val callback =
+                    object : KeyguardUpdateMonitorCallback() {
+                        override fun onLockedOutStateChanged(
+                            biometricSourceType: BiometricSourceType?
+                        ) {
+                            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+                                sendLockoutUpdate()
+                            }
+                        }
+                    }
+                keyguardUpdateMonitor.registerCallback(callback)
+                sendLockoutUpdate()
+                awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
             }
-        keyguardUpdateMonitor.registerCallback(callback)
-        sendLockoutUpdate()
-        awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
-    }
+            .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false)
 
     companion object {
         const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 41574d1..3e17136 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -26,7 +26,6 @@
 import com.android.systemui.log.dagger.BouncerLog
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
-import com.android.systemui.statusbar.phone.KeyguardBouncer
 import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 4639597..cc99eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -32,4 +32,9 @@
     fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
 
     @Binds fun biometricRepository(impl: BiometricRepositoryImpl): BiometricRepository
+
+    @Binds
+    fun deviceEntryFingerprintAuthRepository(
+        impl: DeviceEntryFingerprintAuthRepositoryImpl
+    ): DeviceEntryFingerprintAuthRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index 28c0b28..6020ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
 import com.android.systemui.util.time.SystemClock
@@ -34,6 +35,7 @@
 constructor(
     private val bouncerRepository: KeyguardBouncerRepository,
     private val biometricRepository: BiometricRepository,
+    private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     private val systemClock: SystemClock,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     featureFlags: FeatureFlags,
@@ -99,7 +101,8 @@
             bouncerRepository.isAlternateBouncerUIAvailable.value &&
                 biometricRepository.isFingerprintEnrolled.value &&
                 biometricRepository.isStrongBiometricAllowed.value &&
-                biometricRepository.isFingerprintEnabledByDevicePolicy.value
+                biometricRepository.isFingerprintEnabledByDevicePolicy.value &&
+                !deviceEntryFingerprintAuthRepository.isLockedOut.value
         } else {
             legacyAlternateBouncer != null &&
                 keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
index bb5ac84..8222dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
@@ -25,4 +25,5 @@
      */
     const val EXPANSION_HIDDEN = 1f
     const val EXPANSION_VISIBLE = 0f
+    const val ALPHA_EXPANSION_THRESHOLD = 0.95f
 }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 08d1857..6bfe1a0 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -17,10 +17,12 @@
 package com.android.systemui.notetask
 
 import android.app.KeyguardManager
+import android.content.ActivityNotFoundException
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.UserManager
+import android.util.Log
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
 import com.android.systemui.util.kotlin.getOrNull
@@ -57,7 +59,7 @@
      * If the keyguard is locked, notes will open as a full screen experience. A locked device has
      * no contextual information which let us use the whole screen space available.
      *
-     * If no in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
+     * If not in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
      * collapsed if the notes bubble is already opened.
      *
      * That will let users open other apps in full screen, and take contextual notes.
@@ -68,16 +70,23 @@
         val bubbles = optionalBubbles.getOrNull() ?: return
         val keyguardManager = optionalKeyguardManager.getOrNull() ?: return
         val userManager = optionalUserManager.getOrNull() ?: return
-        val intent = intentResolver.resolveIntent() ?: return
 
         // TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
         if (!userManager.isUserUnlocked) return
 
-        if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
-            context.startActivity(intent)
-        } else {
-            // TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter.
-            bubbles.showOrHideAppBubble(intent)
+        val intent = intentResolver.resolveIntent() ?: return
+
+        // TODO(b/266686199): We should handle when app not available. For now, we log.
+        try {
+            if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
+                context.startActivity(intent)
+            } else {
+                bubbles.showOrHideAppBubble(intent)
+            }
+        } catch (e: ActivityNotFoundException) {
+            val message =
+                "Activity not found for action: ${NoteTaskIntentResolver.ACTION_CREATE_NOTE}."
+            Log.e(TAG, message, e)
         }
     }
 
@@ -106,6 +115,8 @@
     }
 
     companion object {
+        private val TAG = NoteTaskController::class.simpleName.orEmpty()
+
         // TODO(b/254604589): Use final KeyEvent.KEYCODE_* instead.
         const val NOTE_TASK_KEY_EVENT = 311
     }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
index 4b10d69..11dc1d7 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
@@ -16,70 +16,39 @@
 
 package com.android.systemui.notetask
 
-import android.content.ComponentName
+import android.app.role.RoleManager
+import android.content.Context
 import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.PackageManager
-import android.content.pm.PackageManager.ResolveInfoFlags
-import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
 import javax.inject.Inject
 
-/**
- * Class responsible to query all apps and find one that can handle the [ACTION_CREATE_NOTE]. If
- * found, an [Intent] ready for be launched will be returned. Otherwise, returns null.
- *
- * TODO(b/248274123): should be revisited once the notes role is implemented.
- */
 internal class NoteTaskIntentResolver
 @Inject
 constructor(
-    private val packageManager: PackageManager,
+    private val context: Context,
+    private val roleManager: RoleManager,
 ) {
 
     fun resolveIntent(): Intent? {
-        val intent = Intent(ACTION_CREATE_NOTE)
-        val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
-        val infoList = packageManager.queryIntentActivities(intent, flags)
+        val packageName = roleManager.getRoleHoldersAsUser(ROLE_NOTES, context.user).firstOrNull()
 
-        for (info in infoList) {
-            val packageName = info.activityInfo.applicationInfo.packageName ?: continue
-            val activityName = resolveActivityNameForNotesAction(packageName) ?: continue
+        if (packageName.isNullOrEmpty()) return null
 
-            return Intent(ACTION_CREATE_NOTE)
-                .setPackage(packageName)
-                .setComponent(ComponentName(packageName, activityName))
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        }
-
-        return null
-    }
-
-    private fun resolveActivityNameForNotesAction(packageName: String): String? {
-        val intent = Intent(ACTION_CREATE_NOTE).setPackage(packageName)
-        val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
-        val resolveInfo = packageManager.resolveActivity(intent, flags)
-
-        val activityInfo = resolveInfo?.activityInfo ?: return null
-        if (activityInfo.name.isNullOrBlank()) return null
-        if (!activityInfo.exported) return null
-        if (!activityInfo.enabled) return null
-        if (!activityInfo.showWhenLocked) return null
-        if (!activityInfo.turnScreenOn) return null
-
-        return activityInfo.name
+        return Intent(ACTION_CREATE_NOTE)
+            .setPackage(packageName)
+            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            // EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint was
+            // used to start it.
+            .putExtra(INTENT_EXTRA_USE_STYLUS_MODE, true)
     }
 
     companion object {
-        // TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
+        // TODO(b/265912743): Use Intent.ACTION_CREATE_NOTE instead.
         const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
 
         // TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
-        const val NOTE_ROLE = "android.app.role.NOTES"
+        const val ROLE_NOTES = "android.app.role.NOTES"
+
+        // TODO(b/265912743): Use Intent.INTENT_EXTRA_USE_STYLUS_MODE instead.
+        const val INTENT_EXTRA_USE_STYLUS_MODE = "android.intent.extra.USE_STYLUS_MODE"
     }
 }
-
-private val ActivityInfo.showWhenLocked: Boolean
-    get() = flags and ActivityInfo.FLAG_SHOW_WHEN_LOCKED != 0
-
-private val ActivityInfo.turnScreenOn: Boolean
-    get() = flags and ActivityInfo.FLAG_TURN_SCREEN_ON != 0
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 22ce121..ec6a16a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -51,7 +51,7 @@
             featureFlags: FeatureFlags,
             roleManager: RoleManager,
         ): Boolean {
-            val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.NOTE_ROLE)
+            val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.ROLE_NOTES)
             val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
             return isRoleAvailable && isFeatureEnabled
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1151475..dd7ea76 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -30,6 +30,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -652,13 +653,14 @@
     }
 
     private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
-            boolean bouncerShowing, boolean isDozing, boolean panelExpanded) {
+            boolean bouncerShowing, boolean isDozing, boolean panelExpanded, boolean isDreaming) {
         mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
                         keyguardShowing && !keyguardOccluded)
                 .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
                         keyguardShowing && keyguardOccluded)
                 .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing)
                 .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing)
+                .setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming)
                 .commitUpdate(mContext.getDisplayId());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index cce3c64..b6f08f8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -142,6 +142,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;
@@ -207,7 +208,6 @@
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
@@ -3786,7 +3786,8 @@
         //   change due to "unlock hint animation." In this case, fading out the bottom area
         //   would also hide the message that says "swipe to unlock," we don't want to do that.
         float expansionAlpha = MathUtils.map(
-                isUnlockHintRunning() ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f,
+                isUnlockHintRunning() ? 0 : KeyguardBouncerConstants.ALPHA_EXPANSION_THRESHOLD, 1f,
+                0f, 1f,
                 getExpandedFraction());
         float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
         alpha *= mBottomAreaShadeAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index ab2e692..156e4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -563,7 +563,8 @@
                     mCurrentState.keyguardOccluded,
                     mCurrentState.bouncerShowing,
                     mCurrentState.dozing,
-                    mCurrentState.panelExpanded);
+                    mCurrentState.panelExpanded,
+                    mCurrentState.dreaming);
         }
     }
 
@@ -778,6 +779,12 @@
     }
 
     @Override
+    public void setDreaming(boolean dreaming) {
+        mCurrentState.dreaming = dreaming;
+        apply(mCurrentState);
+    }
+
+    @Override
     public void setForcePluginOpen(boolean forceOpen, Object token) {
         if (forceOpen) {
             mCurrentState.forceOpenTokens.add(token);
@@ -904,5 +911,10 @@
         public void onDozingChanged(boolean isDozing) {
             setDozing(isDozing);
         }
+
+        @Override
+        public void onDreamingChanged(boolean isDreaming) {
+            setDreaming(isDreaming);
+        }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
index 736404aa..fed9b84 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
@@ -23,8 +23,8 @@
 import com.android.systemui.statusbar.StatusBarState
 
 /**
- * Represents state of shade window, used by [NotificationShadeWindowControllerImpl].
- * Contains nested class [Buffer] for pretty table logging in bug reports.
+ * Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. Contains
+ * nested class [Buffer] for pretty table logging in bug reports.
  */
 class NotificationShadeWindowState(
     @JvmField var keyguardShowing: Boolean = false,
@@ -55,6 +55,7 @@
     @JvmField var remoteInputActive: Boolean = false,
     @JvmField var forcePluginOpen: Boolean = false,
     @JvmField var dozing: Boolean = false,
+    @JvmField var dreaming: Boolean = false,
     @JvmField var scrimsVisibility: Int = 0,
     @JvmField var backgroundBlurRadius: Int = 0,
 ) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 0b1807d..2ca0b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -143,6 +143,9 @@
     /** Sets the state of whether sysui is dozing or not. */
     default void setDozing(boolean dozing) {}
 
+    /** Sets the state of whether sysui is dreaming or not. */
+    default void setDreaming(boolean dreaming) {}
+
     /** Sets the state of whether plugin open is forced or not. */
     default void setForcePluginOpen(boolean forcePluginOpen, Object token) {}
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 186e6dc..784e2d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -129,6 +129,11 @@
     private boolean mIsDozing;
 
     /**
+     * If the device is currently dreaming or not.
+     */
+    private boolean mIsDreaming;
+
+    /**
      * If the status bar is currently expanded or not.
      */
     private boolean mIsExpanded;
@@ -294,6 +299,29 @@
     }
 
     @Override
+    public boolean setIsDreaming(boolean isDreaming) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "setIsDreaming:" + isDreaming);
+        }
+        if (mIsDreaming == isDreaming) {
+            return false;
+        }
+
+        mIsDreaming = isDreaming;
+
+        synchronized (mListeners) {
+            String tag = getClass().getSimpleName() + "#setIsDreaming";
+            DejankUtils.startDetectingBlockingIpcs(tag);
+            for (RankedListener rl : new ArrayList<>(mListeners)) {
+                rl.mListener.onDreamingChanged(isDreaming);
+            }
+            DejankUtils.stopDetectingBlockingIpcs(tag);
+        }
+
+        return true;
+    }
+
+    @Override
     public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) {
         if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
             if (animated && mDozeAmountTarget == dozeAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index e0cf812..088c568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -99,6 +99,13 @@
     boolean setIsDozing(boolean isDozing);
 
     /**
+     * Update the dreaming state from {@link CentralSurfaces}'s perspective
+     * @param isDreaming whether we are dreaming
+     * @return {@code true} if the state changed, else {@code false}
+     */
+    boolean setIsDreaming(boolean isDreaming);
+
+    /**
      * Changes the current doze amount, also starts the
      * {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 665b1bc..ff2392e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -36,10 +36,12 @@
 import android.view.View
 import android.view.ViewGroup
 import com.android.settingslib.Utils
+import com.android.systemui.Dumpable
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.ActivityStarter
@@ -57,15 +59,14 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.util.concurrency.Execution
 import com.android.systemui.util.settings.SecureSettings
+import java.io.PrintWriter
 import java.util.Optional
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
 /** Controller for managing the smartspace view on the lockscreen */
 @SysUISingleton
-class LockscreenSmartspaceController
-@Inject
-constructor(
+class LockscreenSmartspaceController @Inject constructor(
         private val context: Context,
         private val featureFlags: FeatureFlags,
         private val smartspaceManager: SmartspaceManager,
@@ -78,13 +79,14 @@
         private val statusBarStateController: StatusBarStateController,
         private val deviceProvisionedController: DeviceProvisionedController,
         private val bypassController: KeyguardBypassController,
+        private val dumpManager: DumpManager,
         private val execution: Execution,
         @Main private val uiExecutor: Executor,
         @Background private val bgExecutor: Executor,
         @Main private val handler: Handler,
         optionalPlugin: Optional<BcSmartspaceDataPlugin>,
         optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
-) {
+        ) : Dumpable {
     companion object {
         private const val TAG = "LockscreenSmartspaceController"
     }
@@ -201,6 +203,7 @@
 
     init {
         deviceProvisionedController.addCallback(deviceProvisionedListener)
+        dumpManager.registerDumpable(this)
     }
 
     fun isEnabled(): Boolean {
@@ -441,4 +444,11 @@
         }
         return null
     }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println("Region Samplers: ${regionSamplers.size}")
+        regionSamplers.map { (_, sampler) ->
+            sampler.dump(pw)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
deleted file mode 100644
index d318759..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.phone;
-
-import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.hardware.biometrics.BiometricSourceType;
-import android.os.Handler;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-
-import com.android.internal.policy.SystemBarUtils;
-import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardSecurityModel;
-import com.android.keyguard.KeyguardSecurityView;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
-import com.android.systemui.DejankUtils;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.KeyguardResetCallback;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.ListenerSet;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * A class which manages the primary (pin/pattern/password) bouncer on the lockscreen.
- * @deprecated Use KeyguardBouncerRepository
- */
-@Deprecated
-public class KeyguardBouncer {
-
-    private static final String TAG = "PrimaryKeyguardBouncer";
-    static final long BOUNCER_FACE_DELAY = 1200;
-    public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
-    protected final Context mContext;
-    protected final ViewMediatorCallback mCallback;
-    protected final ViewGroup mContainer;
-    private final FalsingCollector mFalsingCollector;
-    private final DismissCallbackRegistry mDismissCallbackRegistry;
-    private final Handler mHandler;
-    private final List<PrimaryBouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>();
-    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private final KeyguardStateController mKeyguardStateController;
-    private final KeyguardSecurityModel mKeyguardSecurityModel;
-    private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
-    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
-            new KeyguardUpdateMonitorCallback() {
-                @Override
-                public void onStrongAuthStateChanged(int userId) {
-                    mBouncerPromptReason = mCallback.getBouncerPromptReason();
-                }
-
-                @Override
-                public void onLockedOutStateChanged(BiometricSourceType type) {
-                    if (type == BiometricSourceType.FINGERPRINT) {
-                        mBouncerPromptReason = mCallback.getBouncerPromptReason();
-                    }
-                }
-
-                @Override
-                public void onNonStrongBiometricAllowedChanged(int userId) {
-                    mBouncerPromptReason = mCallback.getBouncerPromptReason();
-                }
-            };
-    private final Runnable mRemoveViewRunnable = this::removeView;
-    private final KeyguardBypassController mKeyguardBypassController;
-    private KeyguardHostViewController mKeyguardViewController;
-    private final ListenerSet<KeyguardResetCallback> mResetCallbacks = new ListenerSet<>();
-    private final Runnable mResetRunnable = ()-> {
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.resetSecurityContainer();
-            for (KeyguardResetCallback callback : mResetCallbacks) {
-                callback.onKeyguardReset();
-            }
-        }
-    };
-
-    private int mStatusBarHeight;
-    private float mExpansion = EXPANSION_HIDDEN;
-    private boolean mShowingSoon;
-    private int mBouncerPromptReason;
-    private boolean mIsAnimatingAway;
-    private boolean mIsScrimmed;
-    private boolean mInitialized;
-
-    private KeyguardBouncer(Context context, ViewMediatorCallback callback,
-            ViewGroup container,
-            DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
-            PrimaryBouncerExpansionCallback expansionCallback,
-            KeyguardStateController keyguardStateController,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            KeyguardBypassController keyguardBypassController, @Main Handler handler,
-            KeyguardSecurityModel keyguardSecurityModel,
-            KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
-        mContext = context;
-        mCallback = callback;
-        mContainer = container;
-        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
-        mFalsingCollector = falsingCollector;
-        mDismissCallbackRegistry = dismissCallbackRegistry;
-        mHandler = handler;
-        mKeyguardStateController = keyguardStateController;
-        mKeyguardSecurityModel = keyguardSecurityModel;
-        mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
-        mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
-        mKeyguardBypassController = keyguardBypassController;
-        mExpansionCallbacks.add(expansionCallback);
-    }
-
-    /**
-     * Get the KeyguardBouncer expansion
-     * @return 1=HIDDEN, 0=SHOWING, in between 0 and 1 means the bouncer is in transition.
-     */
-    public float getExpansion() {
-        return mExpansion;
-    }
-
-    /**
-     * Enable/disable only the back button
-     */
-    public void setBackButtonEnabled(boolean enabled) {
-        int vis = mContainer.getSystemUiVisibility();
-        if (enabled) {
-            vis &= ~View.STATUS_BAR_DISABLE_BACK;
-        } else {
-            vis |= View.STATUS_BAR_DISABLE_BACK;
-        }
-        mContainer.setSystemUiVisibility(vis);
-    }
-
-    public void show(boolean resetSecuritySelection) {
-        show(resetSecuritySelection, true /* scrimmed */);
-    }
-
-    /**
-     * Shows the bouncer.
-     *
-     * @param resetSecuritySelection Cleans keyguard view
-     * @param isScrimmed true when the bouncer show show scrimmed, false when the user will be
-     *                 dragging it and translation should be deferred.
-     */
-    public void show(boolean resetSecuritySelection, boolean isScrimmed) {
-        final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
-        if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
-            // In split system user mode, we never unlock system user.
-            return;
-        }
-
-        try {
-            Trace.beginSection("KeyguardBouncer#show");
-
-            ensureView();
-            mIsScrimmed = isScrimmed;
-
-            // On the keyguard, we want to show the bouncer when the user drags up, but it's
-            // not correct to end the falsing session. We still need to verify if those touches
-            // are valid.
-            // Later, at the end of the animation, when the bouncer is at the top of the screen,
-            // onFullyShown() will be called and FalsingManager will stop recording touches.
-            if (isScrimmed) {
-                setExpansion(EXPANSION_VISIBLE);
-            }
-
-            if (resetSecuritySelection) {
-                // showPrimarySecurityScreen() updates the current security method. This is needed
-                // in case we are already showing and the current security method changed.
-                showPrimarySecurityScreen();
-            }
-
-            if (mContainer.getVisibility() == View.VISIBLE || mShowingSoon) {
-                // Calls to reset must resume the ViewControllers when in fullscreen mode
-                if (needsFullscreenBouncer()) {
-                    mKeyguardViewController.onResume();
-                }
-                return;
-            }
-
-            final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
-            final boolean isSystemUser =
-                UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
-            final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
-
-            // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern)
-            // is set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
-            if (allowDismissKeyguard && mKeyguardViewController.dismiss(activeUserId)) {
-                return;
-            }
-
-            // This condition may indicate an error on Android, so log it.
-            if (!allowDismissKeyguard) {
-                Log.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != "
-                        + keyguardUserId);
-            }
-
-            mShowingSoon = true;
-
-            // Split up the work over multiple frames.
-            DejankUtils.removeCallbacks(mResetRunnable);
-            if (mKeyguardStateController.isFaceAuthEnabled()
-                    && !mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                            KeyguardUpdateMonitor.getCurrentUser())
-                    && !needsFullscreenBouncer()
-                    && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
-                            BiometricSourceType.FACE)
-                    && !mKeyguardBypassController.getBypassEnabled()) {
-                mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
-            } else {
-                DejankUtils.postAfterTraversal(mShowRunnable);
-            }
-
-            mKeyguardStateController.notifyBouncerShowing(true /* showing */);
-            dispatchStartingToShow();
-        } finally {
-            Trace.endSection();
-        }
-    }
-
-    public boolean isScrimmed() {
-        return mIsScrimmed;
-    }
-
-    /**
-     * This method must be called at the end of the bouncer animation when
-     * the translation is performed manually by the user, otherwise FalsingManager
-     * will never be notified and its internal state will be out of sync.
-     */
-    private void onFullyShown() {
-        mFalsingCollector.onBouncerShown();
-        if (mKeyguardViewController == null) {
-            Log.e(TAG, "onFullyShown when view was null");
-        } else {
-            mKeyguardViewController.onResume();
-            mContainer.announceForAccessibility(
-                    mKeyguardViewController.getAccessibilityTitleForCurrentMode());
-        }
-    }
-
-    /**
-     * @see #onFullyShown()
-     */
-    private void onFullyHidden() {
-
-    }
-
-    private void setVisibility(@View.Visibility int visibility) {
-        mContainer.setVisibility(visibility);
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.onBouncerVisibilityChanged(visibility);
-        }
-        dispatchVisibilityChanged();
-    }
-
-    private final Runnable mShowRunnable = new Runnable() {
-        @Override
-        public void run() {
-            setVisibility(View.VISIBLE);
-            showPromptReason(mBouncerPromptReason);
-            final CharSequence customMessage = mCallback.consumeCustomMessage();
-            if (customMessage != null) {
-                mKeyguardViewController.showErrorMessage(customMessage);
-            }
-            mKeyguardViewController.appear(mStatusBarHeight);
-            mShowingSoon = false;
-            if (mExpansion == EXPANSION_VISIBLE) {
-                mKeyguardViewController.onResume();
-                mKeyguardViewController.resetSecurityContainer();
-                showPromptReason(mBouncerPromptReason);
-            }
-        }
-    };
-
-    /**
-     * Show a string explaining why the security view needs to be solved.
-     *
-     * @param reason a flag indicating which string should be shown, see
-     *               {@link KeyguardSecurityView#PROMPT_REASON_NONE}
-     *               and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
-     */
-    public void showPromptReason(int reason) {
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.showPromptReason(reason);
-        } else {
-            Log.w(TAG, "Trying to show prompt reason on empty bouncer");
-        }
-    }
-
-    public void showMessage(String message, ColorStateList colorState) {
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.showMessage(message, colorState);
-        } else {
-            Log.w(TAG, "Trying to show message on empty bouncer");
-        }
-    }
-
-    private void cancelShowRunnable() {
-        DejankUtils.removeCallbacks(mShowRunnable);
-        mHandler.removeCallbacks(mShowRunnable);
-        mShowingSoon = false;
-    }
-
-    public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
-        ensureView();
-        setDismissAction(r, cancelAction);
-        show(false /* resetSecuritySelection */);
-    }
-
-    /**
-     * Set the actions to run when the keyguard is dismissed or when the dismiss is cancelled. Those
-     * actions will still be run even if this bouncer is not shown, for instance when authenticating
-     * with an alternate authenticator like the UDFPS.
-     */
-    public void setDismissAction(OnDismissAction r, Runnable cancelAction) {
-        mKeyguardViewController.setOnDismissAction(r, cancelAction);
-    }
-
-    public void hide(boolean destroyView) {
-        Trace.beginSection("KeyguardBouncer#hide");
-        if (isShowing()) {
-            SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
-                    SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
-            mDismissCallbackRegistry.notifyDismissCancelled();
-        }
-        mIsScrimmed = false;
-        mFalsingCollector.onBouncerHidden();
-        mKeyguardStateController.notifyBouncerShowing(false /* showing */);
-        cancelShowRunnable();
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.cancelDismissAction();
-            mKeyguardViewController.cleanUp();
-        }
-        mIsAnimatingAway = false;
-        setVisibility(View.INVISIBLE);
-        if (destroyView) {
-
-            // We have a ViewFlipper that unregisters a broadcast when being detached, which may
-            // be slow because of AM lock contention during unlocking. We can delay it a bit.
-            mHandler.postDelayed(mRemoveViewRunnable, 50);
-        }
-        Trace.endSection();
-    }
-
-    /**
-     * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
-     */
-    public void startPreHideAnimation(Runnable runnable) {
-        mIsAnimatingAway = true;
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.startDisappearAnimation(runnable);
-        } else if (runnable != null) {
-            runnable.run();
-        }
-    }
-
-    /**
-     * Reset the state of the view.
-     */
-    public void reset() {
-        cancelShowRunnable();
-        inflateView();
-        mFalsingCollector.onBouncerHidden();
-    }
-
-    public void onScreenTurnedOff() {
-        if (mKeyguardViewController != null && mContainer.getVisibility() == View.VISIBLE) {
-            mKeyguardViewController.onPause();
-        }
-    }
-
-    public boolean isShowing() {
-        return (mShowingSoon || mContainer.getVisibility() == View.VISIBLE)
-                && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
-    }
-
-    /**
-     * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
-     */
-    public boolean inTransit() {
-        return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
-    }
-
-    /**
-     * @return {@code true} when bouncer's pre-hide animation already started but isn't completely
-     *         hidden yet, {@code false} otherwise.
-     */
-    public boolean isAnimatingAway() {
-        return mIsAnimatingAway;
-    }
-
-    public void prepare() {
-        boolean wasInitialized = mInitialized;
-        ensureView();
-        if (wasInitialized) {
-            showPrimarySecurityScreen();
-        }
-        mBouncerPromptReason = mCallback.getBouncerPromptReason();
-    }
-
-    private void showPrimarySecurityScreen() {
-        mKeyguardViewController.showPrimarySecurityScreen();
-    }
-
-    /**
-     * Current notification panel expansion
-     * @param fraction 0 when notification panel is collapsed and 1 when expanded.
-     * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
-     */
-    public void setExpansion(float fraction) {
-        float oldExpansion = mExpansion;
-        boolean expansionChanged = mExpansion != fraction;
-        mExpansion = fraction;
-        if (mKeyguardViewController != null && !mIsAnimatingAway) {
-            mKeyguardViewController.setExpansion(fraction);
-        }
-
-        if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
-            onFullyShown();
-            dispatchFullyShown();
-        } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
-            DejankUtils.postAfterTraversal(mResetRunnable);
-            /*
-             * There are cases where #hide() was not invoked, such as when
-             * NotificationPanelViewController controls the hide animation. Make sure the state gets
-             * updated by calling #hide() directly.
-             */
-            hide(false /* destroyView */);
-            dispatchFullyHidden();
-        } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
-            dispatchStartingToHide();
-            if (mKeyguardViewController != null) {
-                mKeyguardViewController.onStartingToHide();
-            }
-        }
-
-        if (expansionChanged) {
-            dispatchExpansionChanged();
-        }
-    }
-
-    public boolean willDismissWithAction() {
-        return mKeyguardViewController != null && mKeyguardViewController.hasDismissActions();
-    }
-
-    public int getTop() {
-        if (mKeyguardViewController == null) {
-            return 0;
-        }
-
-        return mKeyguardViewController.getTop();
-    }
-
-    protected void ensureView() {
-        // Removal of the view might be deferred to reduce unlock latency,
-        // in this case we need to force the removal, otherwise we'll
-        // end up in an unpredictable state.
-        boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
-        if (!mInitialized || forceRemoval) {
-            inflateView();
-        }
-    }
-
-    protected void inflateView() {
-        removeView();
-        mHandler.removeCallbacks(mRemoveViewRunnable);
-
-        KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create(mContainer);
-        mKeyguardViewController = component.getKeyguardHostViewController();
-        mKeyguardViewController.init();
-
-        mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
-        setVisibility(View.INVISIBLE);
-
-        final WindowInsets rootInsets = mContainer.getRootWindowInsets();
-        if (rootInsets != null) {
-            mContainer.dispatchApplyWindowInsets(rootInsets);
-        }
-        mInitialized = true;
-    }
-
-    protected void removeView() {
-        mContainer.removeAllViews();
-        mInitialized = false;
-    }
-
-    /**
-     * @return True if and only if the security method should be shown before showing the
-     * notifications on Keyguard, like SIM PIN/PUK.
-     */
-    public boolean needsFullscreenBouncer() {
-        SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
-                KeyguardUpdateMonitor.getCurrentUser());
-        return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
-    }
-
-    /**
-     * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
-     * makes this method much faster.
-     */
-    public boolean isFullscreenBouncer() {
-        if (mKeyguardViewController != null) {
-            SecurityMode mode = mKeyguardViewController.getCurrentSecurityMode();
-            return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
-        }
-        return false;
-    }
-
-    /**
-     * WARNING: This method might cause Binder calls.
-     */
-    public boolean isSecure() {
-        return mKeyguardSecurityModel.getSecurityMode(
-                KeyguardUpdateMonitor.getCurrentUser()) != SecurityMode.None;
-    }
-
-    public boolean shouldDismissOnMenuPressed() {
-        return mKeyguardViewController.shouldEnableMenuKey();
-    }
-
-    public boolean interceptMediaKey(KeyEvent event) {
-        ensureView();
-        return mKeyguardViewController.interceptMediaKey(event);
-    }
-
-    /**
-     * @return true if the pre IME back event should be handled
-     */
-    public boolean dispatchBackKeyEventPreIme() {
-        ensureView();
-        return mKeyguardViewController.dispatchBackKeyEventPreIme();
-    }
-
-    public void notifyKeyguardAuthenticated(boolean strongAuth) {
-        ensureView();
-        mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
-    }
-
-    private void dispatchFullyShown() {
-        for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onFullyShown();
-        }
-    }
-
-    private void dispatchStartingToHide() {
-        for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onStartingToHide();
-        }
-    }
-
-    private void dispatchStartingToShow() {
-        for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onStartingToShow();
-        }
-    }
-
-    private void dispatchFullyHidden() {
-        for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onFullyHidden();
-        }
-    }
-
-    private void dispatchExpansionChanged() {
-        for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onExpansionChanged(mExpansion);
-        }
-    }
-
-    private void dispatchVisibilityChanged() {
-        for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onVisibilityChanged(mContainer.getVisibility() == View.VISIBLE);
-        }
-    }
-
-    /**
-     * Apply keyguard configuration from the currently active resources. This can be called when the
-     * device configuration changes, to re-apply some resources that are qualified on the device
-     * configuration.
-     */
-    public void updateResources() {
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.updateResources();
-        }
-    }
-
-    public void dump(PrintWriter pw) {
-        pw.println("KeyguardBouncer");
-        pw.println("  isShowing(): " + isShowing());
-        pw.println("  mStatusBarHeight: " + mStatusBarHeight);
-        pw.println("  mExpansion: " + mExpansion);
-        pw.println("  mKeyguardViewController; " + mKeyguardViewController);
-        pw.println("  mShowingSoon: " + mShowingSoon);
-        pw.println("  mBouncerPromptReason: " + mBouncerPromptReason);
-        pw.println("  mIsAnimatingAway: " + mIsAnimatingAway);
-        pw.println("  mInitialized: " + mInitialized);
-    }
-
-    /** Update keyguard position based on a tapped X coordinate. */
-    public void updateKeyguardPosition(float x) {
-        if (mKeyguardViewController != null) {
-            mKeyguardViewController.updateKeyguardPosition(x);
-        }
-    }
-
-    public void addKeyguardResetCallback(KeyguardResetCallback callback) {
-        mResetCallbacks.addIfAbsent(callback);
-    }
-
-    public void removeKeyguardResetCallback(KeyguardResetCallback callback) {
-        mResetCallbacks.remove(callback);
-    }
-
-    /**
-     * Adds a callback to listen to bouncer expansion updates.
-     */
-    public void addBouncerExpansionCallback(PrimaryBouncerExpansionCallback callback) {
-        if (!mExpansionCallbacks.contains(callback)) {
-            mExpansionCallbacks.add(callback);
-        }
-    }
-
-    /**
-     * Removes a previously added callback. If the callback was never added, this methood
-     * does nothing.
-     */
-    public void removeBouncerExpansionCallback(PrimaryBouncerExpansionCallback callback) {
-        mExpansionCallbacks.remove(callback);
-    }
-
-    /** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
-    public static class Factory {
-        private final Context mContext;
-        private final ViewMediatorCallback mCallback;
-        private final DismissCallbackRegistry mDismissCallbackRegistry;
-        private final FalsingCollector mFalsingCollector;
-        private final KeyguardStateController mKeyguardStateController;
-        private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-        private final KeyguardBypassController mKeyguardBypassController;
-        private final Handler mHandler;
-        private final KeyguardSecurityModel mKeyguardSecurityModel;
-        private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
-
-        @Inject
-        public Factory(Context context, ViewMediatorCallback callback,
-                DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
-                KeyguardStateController keyguardStateController,
-                KeyguardUpdateMonitor keyguardUpdateMonitor,
-                KeyguardBypassController keyguardBypassController, @Main Handler handler,
-                KeyguardSecurityModel keyguardSecurityModel,
-                KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
-            mContext = context;
-            mCallback = callback;
-            mDismissCallbackRegistry = dismissCallbackRegistry;
-            mFalsingCollector = falsingCollector;
-            mKeyguardStateController = keyguardStateController;
-            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
-            mKeyguardBypassController = keyguardBypassController;
-            mHandler = handler;
-            mKeyguardSecurityModel = keyguardSecurityModel;
-            mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
-        }
-
-        /**
-         * Construct a KeyguardBouncer that will exist in the given container.
-         */
-        public KeyguardBouncer create(ViewGroup container,
-                PrimaryBouncerExpansionCallback expansionCallback) {
-            return new KeyguardBouncer(mContext, mCallback, container,
-                    mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
-                    mKeyguardStateController, mKeyguardUpdateMonitor,
-                    mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
-                    mKeyguardBouncerComponentFactory);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 24ad55d..11863627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -501,7 +501,7 @@
         @VisibleForTesting
         protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) {
             if (mStatusBarPipelineFlags.useNewWifiIcon()) {
-                throw new IllegalStateException("Attempting to add a mobile icon while the new "
+                throw new IllegalStateException("Attempting to add a wifi icon while the new "
                         + "icons are enabled is not supported");
             }
 
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 8e22bf4..fd46571 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -129,7 +129,6 @@
     private final ConfigurationController mConfigurationController;
     private final NavigationModeController mNavigationModeController;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final KeyguardBouncer.Factory mKeyguardBouncerFactory;
     private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
     private final DreamOverlayStateController mDreamOverlayStateController;
     @Nullable
@@ -206,28 +205,28 @@
                 Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
             }
             onBackPressed();
-            if (shouldPlayBackAnimation()) {
+            if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackInvoked();
             }
         }
 
         @Override
         public void onBackProgressed(BackEvent event) {
-            if (shouldPlayBackAnimation()) {
+            if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackProgressed(event);
             }
         }
 
         @Override
         public void onBackCancelled() {
-            if (shouldPlayBackAnimation()) {
+            if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackCancelled();
             }
         }
 
         @Override
         public void onBackStarted(BackEvent event) {
-            if (shouldPlayBackAnimation()) {
+            if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackStarted(event);
             }
         }
@@ -256,7 +255,6 @@
 
     private View mNotificationContainer;
 
-    @Nullable protected KeyguardBouncer mPrimaryBouncer;
     protected boolean mRemoteInputActive;
     private boolean mGlobalActionsVisible = false;
     private boolean mLastGlobalActionsVisible = false;
@@ -281,7 +279,6 @@
     private boolean mLastScreenOffAnimationPlaying;
     private float mQsExpansion;
     final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
-    private boolean mIsModernBouncerEnabled;
     private boolean mIsUnoccludeTransitionFlagEnabled;
     private boolean mIsModernAlternateBouncerEnabled;
     private boolean mIsBackAnimationEnabled;
@@ -329,7 +326,6 @@
             NotificationShadeWindowController notificationShadeWindowController,
             KeyguardStateController keyguardStateController,
             NotificationMediaManager notificationMediaManager,
-            KeyguardBouncer.Factory keyguardBouncerFactory,
             KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
             Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
             Lazy<ShadeController> shadeController,
@@ -352,7 +348,6 @@
         mKeyguardUpdateManager = keyguardUpdateMonitor;
         mStatusBarStateController = sysuiStatusBarStateController;
         mDockManager = dockManager;
-        mKeyguardBouncerFactory = keyguardBouncerFactory;
         mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
         mShadeController = shadeController;
         mLatencyTracker = latencyTracker;
@@ -362,7 +357,6 @@
         mPrimaryBouncerView = primaryBouncerView;
         mFoldAodAnimationController = sysUIUnfoldComponent
                 .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
-        mIsModernBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_BOUNCER);
         mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
         mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
         mAlternateBouncerInteractor = alternateBouncerInteractor;
@@ -381,11 +375,7 @@
         mBiometricUnlockController = biometricUnlockController;
 
         ViewGroup container = mCentralSurfaces.getBouncerContainer();
-        if (mIsModernBouncerEnabled) {
-            mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
-        } else {
-            mPrimaryBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback);
-        }
+        mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
         mNotificationPanelViewController = notificationPanelViewController;
         if (shadeExpansionStateManager != null) {
             shadeExpansionStateManager.addExpansionListener(this);
@@ -552,11 +542,7 @@
          * show if any subsequent events are to be handled.
          */
         if (beginShowingBouncer(event)) {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
-            } else {
-                mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
-            }
+            mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
         }
 
         if (!primaryBouncerIsOrWillBeShowing()) {
@@ -564,17 +550,9 @@
         }
 
         if (mKeyguardStateController.isShowing()) {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.setExpansion(fraction);
-            } else {
-                mPrimaryBouncerInteractor.setPanelExpansion(fraction);
-            }
+            mPrimaryBouncerInteractor.setPanelExpansion(fraction);
         } else {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.setExpansion(EXPANSION_HIDDEN);
-            } else {
-                mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN);
-            }
+            mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN);
         }
     }
 
@@ -604,24 +582,17 @@
 
     /**
      * Shows the notification keyguard or the bouncer depending on
-     * {@link KeyguardBouncer#needsFullscreenBouncer()}.
+     * {@link #needsFullscreenBouncer()}.
      */
     protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
         if (needsFullscreenBouncer() && !mDozing) {
             // The keyguard might be showing (already). So we need to hide it.
             mCentralSurfaces.hideKeyguard();
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.show(true /* resetSecuritySelection */);
-            } else {
-                mPrimaryBouncerInteractor.show(true);
-            }
+            mPrimaryBouncerInteractor.show(true);
         } else {
             mCentralSurfaces.showKeyguard();
             if (hideBouncerWhenShowing) {
                 hideBouncer(false /* destroyView */);
-                if (mPrimaryBouncer != null) {
-                    mPrimaryBouncer.prepare();
-                }
             }
         }
         updateStates();
@@ -648,11 +619,7 @@
      */
     @VisibleForTesting
     void hideBouncer(boolean destroyView) {
-        if (mPrimaryBouncer != null) {
-            mPrimaryBouncer.hide(destroyView);
-        } else {
-            mPrimaryBouncerInteractor.hide();
-        }
+        mPrimaryBouncerInteractor.hide();
         if (mKeyguardStateController.isShowing()) {
             // If we were showing the bouncer and then aborting, we need to also clear out any
             // potential actions unless we actually unlocked.
@@ -671,11 +638,7 @@
         hideAlternateBouncer(false);
 
         if (mKeyguardStateController.isShowing()  && !isBouncerShowing()) {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.show(false /* resetSecuritySelection */, scrimmed);
-            } else {
-                mPrimaryBouncerInteractor.show(scrimmed);
-            }
+            mPrimaryBouncerInteractor.show(scrimmed);
         }
         updateStates();
     }
@@ -708,13 +671,8 @@
                 // instead of the bouncer.
                 if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
                     if (!afterKeyguardGone) {
-                        if (mPrimaryBouncer != null) {
-                            mPrimaryBouncer.setDismissAction(mAfterKeyguardGoneAction,
-                                    mKeyguardGoneCancelAction);
-                        } else {
-                            mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
-                                    mKeyguardGoneCancelAction);
-                        }
+                        mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
+                                mKeyguardGoneCancelAction);
                         mAfterKeyguardGoneAction = null;
                         mKeyguardGoneCancelAction = null;
                     }
@@ -726,22 +684,13 @@
                 if (afterKeyguardGone) {
                     // we'll handle the dismiss action after keyguard is gone, so just show the
                     // bouncer
-                    if (mPrimaryBouncer != null) {
-                        mPrimaryBouncer.show(false /* resetSecuritySelection */);
-                    } else {
-                        mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
-                    }
+                    mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
                 } else {
                     // after authentication success, run dismiss action with the option to defer
                     // hiding the keyguard based on the return value of the OnDismissAction
-                    if (mPrimaryBouncer != null) {
-                        mPrimaryBouncer.showWithDismissAction(mAfterKeyguardGoneAction,
-                                mKeyguardGoneCancelAction);
-                    } else {
-                        mPrimaryBouncerInteractor.setDismissAction(
-                                mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
-                        mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
-                    }
+                    mPrimaryBouncerInteractor.setDismissAction(
+                            mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
+                    mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
                     // bouncer will handle the dismiss action, so we no longer need to track it here
                     mAfterKeyguardGoneAction = null;
                     mKeyguardGoneCancelAction = null;
@@ -841,11 +790,7 @@
 
     @Override
     public void onFinishedGoingToSleep() {
-        if (mPrimaryBouncer != null) {
-            mPrimaryBouncer.onScreenTurnedOff();
-        } else {
-            mPrimaryBouncerInteractor.onScreenTurnedOff();
-        }
+        mPrimaryBouncerInteractor.onScreenTurnedOff();
     }
 
     @Override
@@ -939,11 +884,7 @@
     @Override
     public void startPreHideAnimation(Runnable finishRunnable) {
         if (primaryBouncerIsShowing()) {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.startPreHideAnimation(finishRunnable);
-            } else {
-                mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
-            }
+            mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
             mNotificationPanelViewController.startBouncerPreHideAnimation();
 
             // We update the state (which will show the keyguard) only if an animation will run on
@@ -1051,17 +992,7 @@
     }
 
     public void onThemeChanged() {
-        if (mIsModernBouncerEnabled) {
-            updateResources();
-            return;
-        }
-        boolean wasShowing = primaryBouncerIsShowing();
-        boolean wasScrimmed = primaryBouncerIsScrimmed();
-
-        hideBouncer(true /* destroyView */);
-        mPrimaryBouncer.prepare();
-
-        if (wasShowing) showPrimaryBouncer(wasScrimmed);
+        updateResources();
     }
 
     public void onKeyguardFadedAway() {
@@ -1106,10 +1037,6 @@
      * WARNING: This method might cause Binder calls.
      */
     public boolean isSecure() {
-        if (mPrimaryBouncer != null) {
-            return mPrimaryBouncer.isSecure();
-        }
-
         return mKeyguardSecurityModel.getSecurityMode(
                 KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None;
     }
@@ -1164,10 +1091,8 @@
     }
 
     public boolean isFullscreenBouncer() {
-        if (mPrimaryBouncerView.getDelegate() != null) {
-            return mPrimaryBouncerView.getDelegate().isFullScreenBouncer();
-        }
-        return mPrimaryBouncer != null && mPrimaryBouncer.isFullscreenBouncer();
+        return mPrimaryBouncerView.getDelegate() != null
+                && mPrimaryBouncerView.getDelegate().isFullScreenBouncer();
     }
 
     /**
@@ -1223,17 +1148,9 @@
                 != (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
                 || mFirstUpdate) {
             if (primaryBouncerDismissible || !showing || remoteInputActive) {
-                if (mPrimaryBouncer != null) {
-                    mPrimaryBouncer.setBackButtonEnabled(true);
-                } else {
-                    mPrimaryBouncerInteractor.setBackButtonEnabled(true);
-                }
+                mPrimaryBouncerInteractor.setBackButtonEnabled(true);
             } else {
-                if (mPrimaryBouncer != null) {
-                    mPrimaryBouncer.setBackButtonEnabled(false);
-                } else {
-                    mPrimaryBouncerInteractor.setBackButtonEnabled(false);
-                }
+                mPrimaryBouncerInteractor.setBackButtonEnabled(false);
             }
         }
 
@@ -1327,27 +1244,21 @@
     }
 
     public boolean shouldDismissOnMenuPressed() {
-        if (mPrimaryBouncerView.getDelegate() != null) {
-            return mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed();
-        }
-        return mPrimaryBouncer != null && mPrimaryBouncer.shouldDismissOnMenuPressed();
+        return mPrimaryBouncerView.getDelegate() != null
+                && mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed();
     }
 
     public boolean interceptMediaKey(KeyEvent event) {
-        if (mPrimaryBouncerView.getDelegate() != null) {
-            return mPrimaryBouncerView.getDelegate().interceptMediaKey(event);
-        }
-        return mPrimaryBouncer != null && mPrimaryBouncer.interceptMediaKey(event);
+        return mPrimaryBouncerView.getDelegate() != null
+                && mPrimaryBouncerView.getDelegate().interceptMediaKey(event);
     }
 
     /**
      * @return true if the pre IME back event should be handled
      */
     public boolean dispatchBackKeyEventPreIme() {
-        if (mPrimaryBouncerView.getDelegate() != null) {
-            return mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme();
-        }
-        return mPrimaryBouncer != null && mPrimaryBouncer.dispatchBackKeyEventPreIme();
+        return mPrimaryBouncerView.getDelegate() != null
+                && mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme();
     }
 
     public void readyForKeyguardDone() {
@@ -1393,11 +1304,7 @@
      * fingerprint.
      */
     public void notifyKeyguardAuthenticated(boolean strongAuth) {
-        if (mPrimaryBouncer != null) {
-            mPrimaryBouncer.notifyKeyguardAuthenticated(strongAuth);
-        } else {
-            mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
-        }
+        mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
 
         if (mAlternateBouncerInteractor.isVisibleState()) {
             hideAlternateBouncer(false);
@@ -1412,11 +1319,7 @@
                 mKeyguardMessageAreaController.setMessage(message);
             }
         } else {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.showMessage(message, colorState);
-            } else {
-                mPrimaryBouncerInteractor.showMessage(message, colorState);
-            }
+            mPrimaryBouncerInteractor.showMessage(message, colorState);
         }
     }
 
@@ -1472,11 +1375,7 @@
      * configuration.
      */
     public void updateResources() {
-        if (mPrimaryBouncer != null) {
-            mPrimaryBouncer.updateResources();
-        } else {
-            mPrimaryBouncerInteractor.updateResources();
-        }
+        mPrimaryBouncerInteractor.updateResources();
     }
 
     public void dump(PrintWriter pw) {
@@ -1494,11 +1393,6 @@
             pw.println("      " + callback);
         }
 
-        if (mPrimaryBouncer != null) {
-            pw.println("PrimaryBouncer:");
-            mPrimaryBouncer.dump(pw);
-        }
-
         if (mOccludingAppBiometricUI != null) {
             pw.println("mOccludingAppBiometricUI:");
             mOccludingAppBiometricUI.dump(pw);
@@ -1548,11 +1442,6 @@
         }
     }
 
-    @Nullable
-    public KeyguardBouncer getPrimaryBouncer() {
-        return mPrimaryBouncer;
-    }
-
     /**
      * For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently
      * showing.
@@ -1571,11 +1460,7 @@
 
     /** Update keyguard position based on a tapped X coordinate. */
     public void updateKeyguardPosition(float x) {
-        if (mPrimaryBouncer != null) {
-            mPrimaryBouncer.updateKeyguardPosition(x);
-        } else {
-            mPrimaryBouncerInteractor.setKeyguardPosition(x);
-        }
+        mPrimaryBouncerInteractor.setKeyguardPosition(x);
     }
 
     private static class DismissWithActionRequest {
@@ -1615,56 +1500,35 @@
      * Returns if bouncer expansion is between 0 and 1 non-inclusive.
      */
     public boolean isPrimaryBouncerInTransit() {
-        if (mPrimaryBouncer != null) {
-            return mPrimaryBouncer.inTransit();
-        } else {
-            return mPrimaryBouncerInteractor.isInTransit();
-        }
+        return mPrimaryBouncerInteractor.isInTransit();
     }
 
     /**
      * Returns if bouncer is showing
      */
     public boolean primaryBouncerIsShowing() {
-        if (mPrimaryBouncer != null) {
-            return mPrimaryBouncer.isShowing();
-        } else {
-            return mPrimaryBouncerInteractor.isFullyShowing();
-        }
+        return mPrimaryBouncerInteractor.isFullyShowing();
     }
 
     /**
      * Returns if bouncer is scrimmed
      */
     public boolean primaryBouncerIsScrimmed() {
-        if (mPrimaryBouncer != null) {
-            return mPrimaryBouncer.isScrimmed();
-        } else {
-            return mPrimaryBouncerInteractor.isScrimmed();
-        }
+        return mPrimaryBouncerInteractor.isScrimmed();
     }
 
     /**
      * Returns if bouncer is animating away
      */
     public boolean bouncerIsAnimatingAway() {
-        if (mPrimaryBouncer != null) {
-            return mPrimaryBouncer.isAnimatingAway();
-        } else {
-            return mPrimaryBouncerInteractor.isAnimatingAway();
-        }
-
+        return mPrimaryBouncerInteractor.isAnimatingAway();
     }
 
     /**
      * Returns if bouncer will dismiss with action
      */
     public boolean primaryBouncerWillDismissWithAction() {
-        if (mPrimaryBouncer != null) {
-            return mPrimaryBouncer.willDismissWithAction();
-        } else {
-            return mPrimaryBouncerInteractor.willDismissWithAction();
-        }
+        return mPrimaryBouncerInteractor.willDismissWithAction();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index ae48c2d3..50cce45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -17,5 +17,5 @@
 
 public interface StatusBarWindowCallback {
     void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
-            boolean isDozing, boolean panelExpanded);
+            boolean isDozing, boolean panelExpanded, boolean isDreaming);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
index d3ff357..491f3a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -97,15 +97,20 @@
         )
     }
 
-    fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
+    fun logOnCapabilitiesChanged(
+        network: Network,
+        networkCapabilities: NetworkCapabilities,
+        isDefaultNetworkCallback: Boolean,
+    ) {
         buffer.log(
             SB_LOGGING_TAG,
             LogLevel.INFO,
             {
+                bool1 = isDefaultNetworkCallback
                 int1 = network.getNetId()
                 str1 = networkCapabilities.toString()
             },
-            { "onCapabilitiesChanged: net=$int1 capabilities=$str1" }
+            { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index d26499c..8669047 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -114,13 +114,17 @@
                             network: Network,
                             networkCapabilities: NetworkCapabilities
                         ) {
+                            logger.logOnCapabilitiesChanged(
+                                network,
+                                networkCapabilities,
+                                isDefaultNetworkCallback = true,
+                            )
+
                             // This method will always be called immediately after the network
                             // becomes the default, in addition to any time the capabilities change
                             // while the network is the default.
-                            // If this network contains valid wifi info, then wifi is the default
-                            // network.
-                            val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
-                            trySend(wifiInfo != null)
+                            // If this network is a wifi network, then wifi is the default network.
+                            trySend(isWifiNetwork(networkCapabilities))
                         }
 
                         override fun onLost(network: Network) {
@@ -152,7 +156,11 @@
                             network: Network,
                             networkCapabilities: NetworkCapabilities
                         ) {
-                            logger.logOnCapabilitiesChanged(network, networkCapabilities)
+                            logger.logOnCapabilitiesChanged(
+                                network,
+                                networkCapabilities,
+                                isDefaultNetworkCallback = false,
+                            )
 
                             wifiNetworkChangeEvents.tryEmit(Unit)
 
@@ -253,16 +261,30 @@
             networkCapabilities: NetworkCapabilities
         ): WifiInfo? {
             return when {
-                networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
-                    networkCapabilities.transportInfo as WifiInfo?
                 networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
                     // Sometimes, cellular networks can act as wifi networks (known as VCN --
                     // virtual carrier network). So, see if this cellular network has wifi info.
                     Utils.tryGetWifiInfoForVcn(networkCapabilities)
+                networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
+                    if (networkCapabilities.transportInfo is WifiInfo) {
+                        networkCapabilities.transportInfo as WifiInfo
+                    } else {
+                        null
+                    }
                 else -> null
             }
         }
 
+        /** True if these capabilities represent a wifi network. */
+        private fun isWifiNetwork(networkCapabilities: NetworkCapabilities): Boolean {
+            return when {
+                networkCapabilities.hasTransport(TRANSPORT_WIFI) -> true
+                networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
+                    Utils.tryGetWifiInfoForVcn(networkCapabilities) != null
+                else -> false
+            }
+        }
+
         private fun createWifiNetworkModel(
             wifiInfo: WifiInfo,
             network: Network,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index 9946b4b..5dcafb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.policy;
 
 import android.annotation.WorkerThread;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCharacteristics;
@@ -255,7 +254,6 @@
                 setTorchMode(enabled);
                 mSecureSettings.putInt(Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
                 mSecureSettings.putInt(Secure.FLASHLIGHT_ENABLED, enabled ? 1 : 0);
-                mBroadcastSender.sendBroadcast(new Intent(ACTION_FLASHLIGHT_CHANGED));
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 7033ccd..5d896cb 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -236,7 +236,8 @@
 
         // Store callback in a field so it won't get GC'd
         mStatusBarWindowCallback =
-                (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) ->
+                (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded,
+                        isDreaming) ->
                         mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
         notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 00b2fbe..dbedba0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -23,6 +23,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
@@ -86,6 +87,7 @@
     @Mock private lateinit var smallLogBuffer: LogBuffer
     @Mock private lateinit var largeLogBuffer: LogBuffer
     private lateinit var underTest: ClockEventController
+    @Mock private lateinit var dumpManager: DumpManager
 
     @Before
     fun setUp() {
@@ -113,7 +115,8 @@
             bgExecutor,
             smallLogBuffer,
             largeLogBuffer,
-            featureFlags
+            featureFlags,
+            dumpManager
         )
         underTest.clock = clock
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 86cd022..d1650b7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -17,7 +17,6 @@
 package com.android.keyguard;
 
 import static android.app.StatusBarManager.SESSION_KEYGUARD;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
@@ -41,7 +40,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -237,8 +235,6 @@
     @Mock
     private UiEventLogger mUiEventLogger;
     @Mock
-    private PowerManager mPowerManager;
-    @Mock
     private GlobalSettings mGlobalSettings;
     private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
     @Mock
@@ -858,6 +854,32 @@
     }
 
     @Test
+    public void faceUnlockDoesNotRunWhenDeviceIsGoingToSleepWithAssistantVisible() {
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
+        mKeyguardUpdateMonitor.setAssistantVisible(true);
+
+        verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+        mTestableLooper.processAllMessages();
+        clearInvocations(mFaceManager);
+
+        // Device going to sleep while assistant is visible
+        mKeyguardUpdateMonitor.handleStartedGoingToSleep(0);
+        mKeyguardUpdateMonitor.handleFinishedGoingToSleep(0);
+        mTestableLooper.moveTimeForward(DEFAULT_CANCEL_SIGNAL_TIMEOUT);
+        mTestableLooper.processAllMessages();
+
+        mKeyguardUpdateMonitor.handleKeyguardReset();
+
+        assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
+        verify(mFaceManager, never()).authenticate(any(),
+                any(),
+                any(),
+                any(),
+                anyInt(),
+                anyBoolean());
+    }
+
+    @Test
     public void testIgnoresAuth_whenTrustAgentOnKeyguard_withoutBypass() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
         mTestableLooper.processAllMessages();
@@ -1884,28 +1906,6 @@
     }
 
     @Test
-    public void testFingerAcquired_wakesUpPowerManager() {
-        cleanupKeyguardUpdateMonitor();
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.kg_wake_on_acquire_start, true);
-        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
-        fingerprintAcquireStart();
-
-        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
-    }
-
-    @Test
-    public void testFingerAcquired_doesNotWakeUpPowerManager() {
-        cleanupKeyguardUpdateMonitor();
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.kg_wake_on_acquire_start, false);
-        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
-        fingerprintAcquireStart();
-
-        verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
-    }
-
-    @Test
     public void testDreamingStopped_faceDoesNotRun() {
         mKeyguardUpdateMonitor.dispatchDreamingStopped();
         mTestableLooper.processAllMessages();
@@ -2386,11 +2386,6 @@
                 .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
     }
 
-    private void fingerprintAcquireStart() {
-        mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
-                .onAuthenticationAcquired(FINGERPRINT_ACQUIRED_START);
-    }
-
     private void deviceInPostureStateOpened() {
         mKeyguardUpdateMonitor.mPostureCallback.onPostureChanged(DEVICE_POSTURE_OPENED);
     }
@@ -2537,7 +2532,7 @@
                     mAuthController, mTelephonyListenerManager,
                     mInteractionJankMonitor, mLatencyTracker, mActiveUnlockConfig,
                     mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
-                    mPowerManager, mTrustManager, mSubscriptionManager, mUserManager,
+                    mTrustManager, mSubscriptionManager, mUserManager,
                     mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
                     mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
                     mFaceWakeUpTriggersConfig, mDevicePostureController,
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 b92c5d0..fd931b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -51,14 +51,24 @@
 import android.view.WindowMetrics
 import androidx.test.filters.SmallTest
 import com.airbnb.lottie.LottieAnimationView
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.ViewMediatorCallback
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.SysuiTestableContext
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags.MODERN_ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestCoroutineScope
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -101,6 +111,9 @@
     @Captor lateinit var overlayCaptor: ArgumentCaptor<View>
     @Captor lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
 
+    private lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
+    private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+    private val featureFlags = FakeFeatureFlags()
     private val executor = FakeExecutor(FakeSystemClock())
     private lateinit var overlayController: ISidefpsController
     private lateinit var sideFpsController: SideFpsController
@@ -121,6 +134,24 @@
 
     @Before
     fun setup() {
+        featureFlags.set(MODERN_ALTERNATE_BOUNCER, true)
+        keyguardBouncerRepository =
+            KeyguardBouncerRepository(
+                mock(ViewMediatorCallback::class.java),
+                FakeSystemClock(),
+                TestCoroutineScope(),
+                mock(TableLogBuffer::class.java),
+            )
+        alternateBouncerInteractor =
+            AlternateBouncerInteractor(
+                keyguardBouncerRepository,
+                FakeBiometricRepository(),
+                FakeDeviceEntryFingerprintAuthRepository(),
+                FakeSystemClock(),
+                mock(KeyguardUpdateMonitor::class.java),
+                featureFlags,
+            )
+
         context.addMockSystemService(DisplayManager::class.java, displayManager)
         context.addMockSystemService(WindowManager::class.java, windowManager)
 
@@ -217,7 +248,10 @@
                 displayManager,
                 executor,
                 handler,
-                dumpManager
+                alternateBouncerInteractor,
+                TestCoroutineScope(),
+                featureFlags,
+                dumpManager,
             )
 
         overlayController =
@@ -507,6 +541,26 @@
 
     private fun verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible: Boolean) {
         sideFpsController.overlayOffsets = sensorLocation
+    }
+
+    fun alternateBouncerVisibility_showAndHideSideFpsUI() = testWithDisplay {
+        // WHEN alternate bouncer is visible
+        keyguardBouncerRepository.setAlternateVisible(true)
+        executor.runAllReady()
+
+        // THEN side fps shows UI
+        verify(windowManager).addView(any(), any())
+        verify(windowManager, never()).removeView(any())
+
+        // WHEN alternate bouncer is no longer visible
+        keyguardBouncerRepository.setAlternateVisible(false)
+        executor.runAllReady()
+
+        // THEN side fps UI is hidden
+        verify(windowManager).removeView(any())
+    }
+
+    private fun hidesWithTaskbar(visible: Boolean) {
         overlayController.show(SENSOR_ID, REASON_UNKNOWN)
         executor.runAllReady()
 
@@ -515,7 +569,7 @@
 
         verify(windowManager).addView(any(), any())
         verify(windowManager, never()).removeView(any())
-        verify(sideFpsView).visibility = if (sfpsViewVisible) View.VISIBLE else View.GONE
+        verify(sideFpsView).visibility = if (visible) View.VISIBLE else View.GONE
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
index 9c32c38..498cc29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
@@ -37,7 +37,6 @@
 import com.android.systemui.shade.ShadeExpansionListener;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
@@ -71,7 +70,6 @@
     protected @Mock SystemUIDialogManager mDialogManager;
     protected @Mock UdfpsController mUdfpsController;
     protected @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
-    protected @Mock KeyguardBouncer mBouncer;
     protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     protected @Mock AlternateBouncerInteractor mAlternateBouncerInteractor;
 
@@ -152,8 +150,6 @@
         mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer);
         mFeatureFlags.set(Flags.MODERN_ALTERNATE_BOUNCER, useModernBouncer);
         mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, useExpandedOverlay);
-        when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(
-                useModernBouncer ? null : mBouncer);
         UdfpsKeyguardViewController controller = new UdfpsKeyguardViewController(
                 mView,
                 mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 7715f7f..f437a8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -32,24 +32,17 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
 import com.android.systemui.shade.ShadeExpansionListener;
 import com.android.systemui.statusbar.StatusBarState;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
-    private @Captor ArgumentCaptor<PrimaryBouncerExpansionCallback>
-            mBouncerExpansionCallbackCaptor;
-    private PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
-
     @Override
     public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
         return createUdfpsKeyguardViewController(/* useModernBouncer */ false,
@@ -62,11 +55,9 @@
         captureStatusBarStateListeners();
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
 
-        captureBouncerExpansionCallback();
         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
         when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true);
-        mBouncerExpansionCallback.onVisibilityChanged(true);
-
+        when(mView.getUnpausedAlpha()).thenReturn(0);
         assertTrue(mController.shouldPauseAuth());
     }
 
@@ -304,11 +295,6 @@
         verify(mView, atLeastOnce()).setPauseAuth(false);
     }
 
-    private void captureBouncerExpansionCallback() {
-        verify(mBouncer).addBouncerExpansionCallback(mBouncerExpansionCallbackCaptor.capture());
-        mBouncerExpansionCallback = mBouncerExpansionCallbackCaptor.getValue();
-    }
-
     @Test
     // TODO(b/259264861): Tracking Bug
     public void testUdfpsExpandedOverlayOn() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 9060922..81a6bc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -91,6 +92,7 @@
             AlternateBouncerInteractor(
                 keyguardBouncerRepository,
                 mock(BiometricRepository::class.java),
+                mock(DeviceEntryFingerprintAuthRepository::class.java),
                 mock(SystemClock::class.java),
                 mock(KeyguardUpdateMonitor::class.java),
                 mock(FeatureFlags::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index bdd496e..71c335e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.clipboardoverlay;
 
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
-
 import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE;
 
 import static org.junit.Assert.assertEquals;
@@ -33,7 +31,6 @@
 import android.content.ClipDescription;
 import android.content.ClipboardManager;
 import android.os.PersistableBundle;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 
 import androidx.test.filters.SmallTest;
@@ -41,9 +38,6 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -63,18 +57,11 @@
     @Mock
     private ClipboardManager mClipboardManager;
     @Mock
-    private ClipboardOverlayControllerLegacyFactory mClipboardOverlayControllerLegacyFactory;
-    @Mock
-    private ClipboardOverlayControllerLegacy mOverlayControllerLegacy;
-    @Mock
     private ClipboardOverlayController mOverlayController;
     @Mock
     private ClipboardToast mClipboardToast;
     @Mock
     private UiEventLogger mUiEventLogger;
-    @Mock
-    private FeatureFlags mFeatureFlags;
-    private DeviceConfigProxyFake mDeviceConfigProxy;
 
     private ClipData mSampleClipData;
     private String mSampleSource = "Example source";
@@ -97,8 +84,6 @@
         mOverlayControllerProvider = () -> mOverlayController;
 
         MockitoAnnotations.initMocks(this);
-        when(mClipboardOverlayControllerLegacyFactory.create(any()))
-                .thenReturn(mOverlayControllerLegacy);
         when(mClipboardManager.hasPrimaryClip()).thenReturn(true);
         Settings.Secure.putInt(
                 mContext.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 1);
@@ -108,26 +93,13 @@
         when(mClipboardManager.getPrimaryClip()).thenReturn(mSampleClipData);
         when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource);
 
-        mDeviceConfigProxy = new DeviceConfigProxyFake();
-
-        mClipboardListener = new ClipboardListener(getContext(), mDeviceConfigProxy,
-                mOverlayControllerProvider, mClipboardOverlayControllerLegacyFactory,
-                mClipboardToast, mClipboardManager, mUiEventLogger, mFeatureFlags);
+        mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider,
+                mClipboardToast, mClipboardManager, mUiEventLogger);
     }
 
-    @Test
-    public void test_disabled() {
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "false", false);
-        mClipboardListener.start();
-        verifyZeroInteractions(mClipboardManager);
-        verifyZeroInteractions(mUiEventLogger);
-    }
 
     @Test
-    public void test_enabled() {
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "true", false);
+    public void test_initialization() {
         mClipboardListener.start();
         verify(mClipboardManager).addPrimaryClipChangedListener(any());
         verifyZeroInteractions(mUiEventLogger);
@@ -135,45 +107,6 @@
 
     @Test
     public void test_consecutiveCopies() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(false);
-
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "true", false);
-        mClipboardListener.start();
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mClipboardOverlayControllerLegacyFactory).create(any());
-
-        verify(mOverlayControllerLegacy).setClipData(
-                mClipDataCaptor.capture(), mStringCaptor.capture());
-
-        assertEquals(mSampleClipData, mClipDataCaptor.getValue());
-        assertEquals(mSampleSource, mStringCaptor.getValue());
-
-        verify(mOverlayControllerLegacy).setOnSessionCompleteListener(mRunnableCaptor.capture());
-
-        // Should clear the overlay controller
-        mRunnableCaptor.getValue().run();
-
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mClipboardOverlayControllerLegacyFactory, times(2)).create(any());
-
-        // Not calling the runnable here, just change the clip again and verify that the overlay is
-        // NOT recreated.
-
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mClipboardOverlayControllerLegacyFactory, times(2)).create(any());
-        verifyZeroInteractions(mOverlayControllerProvider);
-    }
-
-    @Test
-    public void test_consecutiveCopies_new() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(true);
-
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "true", false);
         mClipboardListener.start();
         mClipboardListener.onPrimaryClipChanged();
 
@@ -200,7 +133,6 @@
         mClipboardListener.onPrimaryClipChanged();
 
         verify(mOverlayControllerProvider, times(2)).get();
-        verifyZeroInteractions(mClipboardOverlayControllerLegacyFactory);
     }
 
     @Test
@@ -231,23 +163,6 @@
 
     @Test
     public void test_logging_enterAndReenter() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(false);
-
-        mClipboardListener.start();
-
-        mClipboardListener.onPrimaryClipChanged();
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mUiEventLogger, times(1)).log(
-                ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED, 0, mSampleSource);
-        verify(mUiEventLogger, times(1)).log(
-                ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED, 0, mSampleSource);
-    }
-
-    @Test
-    public void test_logging_enterAndReenter_new() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(true);
-
         mClipboardListener.start();
 
         mClipboardListener.onPrimaryClipChanged();
@@ -271,6 +186,5 @@
                 ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource);
         verify(mClipboardToast, times(1)).showCopiedToast();
         verifyZeroInteractions(mOverlayControllerProvider);
-        verifyZeroInteractions(mClipboardOverlayControllerLegacyFactory);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index ed40c90..85f9961 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -20,6 +20,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
 import android.content.pm.ServiceInfo
 import android.os.UserHandle
 import android.service.controls.ControlsProviderService
@@ -95,6 +96,7 @@
     @Mock lateinit var dumpManager: DumpManager
     @Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
     @Mock lateinit var featureFlags: FeatureFlags
+    @Mock lateinit var packageManager: PackageManager
     val sharedPreferences = FakeSharedPreferences()
     lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
 
@@ -124,6 +126,7 @@
             ControlsUiControllerImpl(
                 Lazy { controlsController },
                 context,
+                packageManager,
                 uiExecutor,
                 bgExecutor,
                 Lazy { controlsListingController },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
new file mode 100644
index 0000000..dbaf94f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.controls.ui
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class OverflowMenuAdapterTest : SysuiTestCase() {
+
+    @Test
+    fun testGetItemId() {
+        val ids = listOf(27L, 73L)
+        val labels = listOf("first", "second")
+        val adapter =
+            OverflowMenuAdapter(
+                context,
+                layoutId = 0,
+                labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
+            ) { true }
+
+        ids.forEachIndexed { index, id -> assertThat(adapter.getItemId(index)).isEqualTo(id) }
+    }
+
+    @Test
+    fun testCheckEnabled() {
+        val ids = listOf(27L, 73L)
+        val labels = listOf("first", "second")
+        val adapter =
+            OverflowMenuAdapter(
+                context,
+                layoutId = 0,
+                labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
+            ) { position -> position == 0 }
+
+        assertThat(adapter.isEnabled(0)).isTrue()
+        assertThat(adapter.isEnabled(1)).isFalse()
+    }
+}
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 ff883eb..84c9786 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -39,8 +39,6 @@
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
 import com.android.systemui.statusbar.BlurUtils;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -81,12 +79,6 @@
     BlurUtils mBlurUtils;
 
     @Mock
-    StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-
-    @Mock
-    KeyguardBouncer mBouncer;
-
-    @Mock
     ViewRootImpl mViewRoot;
 
     @Mock
@@ -106,7 +98,6 @@
 
         when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
         when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
-        when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(mBouncer);
         when(mDreamOverlayContainerView.getViewRootImpl()).thenReturn(mViewRoot);
 
         mController = new DreamOverlayContainerViewController(
@@ -114,7 +105,6 @@
                 mComplicationHostViewController,
                 mDreamOverlayContentView,
                 mDreamOverlayStatusBarViewController,
-                mStatusBarKeyguardViewManager,
                 mBlurUtils,
                 mHandler,
                 mResources,
@@ -170,7 +160,8 @@
         final ArgumentCaptor<PrimaryBouncerExpansionCallback> bouncerExpansionCaptor =
                 ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
         mController.onViewAttached();
-        verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
+        verify(mPrimaryBouncerCallbackInteractor).addBouncerExpansionCallback(
+                bouncerExpansionCaptor.capture());
 
         bouncerExpansionCaptor.getValue().onExpansionChanged(0.5f);
         verify(mBlurUtils, never()).applyBlur(eq(mViewRoot), anyInt(), eq(false));
@@ -181,7 +172,8 @@
         final ArgumentCaptor<PrimaryBouncerExpansionCallback> bouncerExpansionCaptor =
                 ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
         mController.onViewAttached();
-        verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
+        verify(mPrimaryBouncerCallbackInteractor).addBouncerExpansionCallback(
+                bouncerExpansionCaptor.capture());
 
         final float blurRadius = 1337f;
         when(mBlurUtils.blurRadiusOfRatio(anyFloat())).thenReturn(blurRadius);
@@ -217,6 +209,27 @@
     }
 
     @Test
+    public void testSkipEntryAnimationsWhenExitingLowLight() {
+        ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
+        when(mStateController.isLowLightActive()).thenReturn(false);
+
+        // Call onInit so that the callback is added.
+        mController.onInit();
+        verify(mStateController).addCallback(callbackCaptor.capture());
+
+        // Send the signal that low light is exiting
+        callbackCaptor.getValue().onExitLowLight();
+
+        // View is attached to trigger animations.
+        mController.onViewAttached();
+
+        // Entry animations should be started then immediately ended to skip to the end.
+        verify(mAnimationsController).startEntryAnimations();
+        verify(mAnimationsController).endAnimations();
+    }
+
+    @Test
     public void testCancelDreamEntryAnimationsOnDetached() {
         mController.onViewAttached();
         mController.onViewDetached();
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 ee989d1..b7d0f29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -251,6 +251,30 @@
     }
 
     @Test
+    public void testNotifyLowLightExit() {
+        final DreamOverlayStateController stateController =
+                new DreamOverlayStateController(mExecutor, true);
+
+        stateController.addCallback(mCallback);
+        mExecutor.runAllReady();
+        assertThat(stateController.isLowLightActive()).isFalse();
+
+        // Turn low light on then off to trigger the exiting callback.
+        stateController.setLowLightActive(true);
+        stateController.setLowLightActive(false);
+
+        // Callback was only called once, when
+        mExecutor.runAllReady();
+        verify(mCallback, times(1)).onExitLowLight();
+        assertThat(stateController.isLowLightActive()).isFalse();
+
+        // Set with false again, which should not cause the callback to trigger again.
+        stateController.setLowLightActive(false);
+        mExecutor.runAllReady();
+        verify(mCallback, times(1)).onExitLowLight();
+    }
+
+    @Test
     public void testNotifyEntryAnimationsFinishedChanged() {
         final DreamOverlayStateController stateController =
                 new DreamOverlayStateController(mExecutor, true);
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
new file mode 100644
index 0000000..19347c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.dreams.conditions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.condition.Condition;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamConditionTest extends SysuiTestCase {
+    @Mock
+    Context mContext;
+
+    @Mock
+    Condition.Callback mCallback;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Ensure a dreaming state immediately triggers the condition.
+     */
+    @Test
+    public void testInitialState() {
+        final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
+        when(mContext.registerReceiver(any(), any())).thenReturn(intent);
+        final DreamCondition condition = new DreamCondition(mContext);
+        condition.addCallback(mCallback);
+        condition.start();
+
+        verify(mCallback).onConditionChanged(eq(condition));
+        assertThat(condition.isConditionMet()).isTrue();
+    }
+
+    /**
+     * Ensure that changing dream state triggers condition.
+     */
+    @Test
+    public void testChange() {
+        final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
+        final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        when(mContext.registerReceiver(receiverCaptor.capture(), any())).thenReturn(intent);
+        final DreamCondition condition = new DreamCondition(mContext);
+        condition.addCallback(mCallback);
+        condition.start();
+        clearInvocations(mCallback);
+        receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
+        verify(mCallback).onConditionChanged(eq(condition));
+        assertThat(condition.isConditionMet()).isFalse();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index c0af0cb..fb54d6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -62,6 +62,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -184,6 +185,7 @@
                 mainDispatcher = testDispatcher,
                 backgroundHandler = backgroundHandler,
             )
+        underTest.mainDispatcher = UnconfinedTestDispatcher()
 
         underTest.attachInfoForTesting(
             context,
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 8da4eae..58cdec4 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
@@ -19,6 +19,7 @@
 
 import android.app.StatusBarManager
 import android.content.Context
+import android.content.pm.PackageManager
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraGestureHelper
@@ -32,7 +33,6 @@
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.mockito.Mock
-import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
@@ -43,16 +43,19 @@
 
     @Mock private lateinit var cameraGestureHelper: CameraGestureHelper
     @Mock private lateinit var context: Context
+    @Mock private lateinit var packageManager: PackageManager
 
     private lateinit var underTest: CameraQuickAffordanceConfig
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        setLaunchable(true)
 
         underTest =
             CameraQuickAffordanceConfig(
                 context,
+                packageManager,
             ) {
                 cameraGestureHelper
             }
@@ -86,6 +89,7 @@
     }
 
     private fun setLaunchable(isLaunchable: Boolean) {
-        whenever(cameraGestureHelper.canCameraGestureBeLaunched(anyInt())).thenReturn(isLaunchable)
+        whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
+            .thenReturn(isLaunchable)
     }
 }
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 c4ae2db..9203f05 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
@@ -55,7 +55,11 @@
         MockitoAnnotations.initMocks(this)
         testScope = TestScope()
 
-        underTest = DeviceEntryFingerprintAuthRepositoryImpl(keyguardUpdateMonitor)
+        underTest =
+            DeviceEntryFingerprintAuthRepositoryImpl(
+                keyguardUpdateMonitor,
+                testScope.backgroundScope,
+            )
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 1da7241..68fff26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.util.time.FakeSystemClock
@@ -46,6 +47,8 @@
     private lateinit var underTest: AlternateBouncerInteractor
     private lateinit var bouncerRepository: KeyguardBouncerRepository
     private lateinit var biometricRepository: FakeBiometricRepository
+    private lateinit var deviceEntryFingerprintAuthRepository:
+        FakeDeviceEntryFingerprintAuthRepository
     @Mock private lateinit var systemClock: SystemClock
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var bouncerLogger: TableLogBuffer
@@ -62,11 +65,13 @@
                 bouncerLogger,
             )
         biometricRepository = FakeBiometricRepository()
+        deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
         featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) }
         underTest =
             AlternateBouncerInteractor(
                 bouncerRepository,
                 biometricRepository,
+                deviceEntryFingerprintAuthRepository,
                 systemClock,
                 keyguardUpdateMonitor,
                 featureFlags,
@@ -112,6 +117,14 @@
     }
 
     @Test
+    fun canShowAlternateBouncerForFingerprint_fingerprintLockedOut() {
+        givenCanShowAlternateBouncer()
+        deviceEntryFingerprintAuthRepository.setLockedOut(true)
+
+        assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+    }
+
+    @Test
     fun show_whenCanShow() {
         givenCanShowAlternateBouncer()
 
@@ -148,6 +161,7 @@
         biometricRepository.setFingerprintEnrolled(true)
         biometricRepository.setStrongBiometricAllowed(true)
         biometricRepository.setFingerprintEnabledByDevicePolicy(true)
+        deviceEntryFingerprintAuthRepository.setLockedOut(false)
     }
 
     private fun givenCannotShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
index bbe60f4..18be92b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
@@ -16,17 +16,14 @@
 
 package com.android.systemui.notetask
 
-import android.content.ComponentName
+import android.app.role.RoleManager
 import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
-import android.content.pm.PackageManager.ResolveInfoFlags
-import android.content.pm.ResolveInfo
 import android.test.suitebuilder.annotation.SmallTest
 import androidx.test.runner.AndroidJUnit4
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -47,172 +44,39 @@
 internal class NoteTaskIntentResolverTest : SysuiTestCase() {
 
     @Mock lateinit var packageManager: PackageManager
+    @Mock lateinit var roleManager: RoleManager
 
-    private lateinit var resolver: NoteTaskIntentResolver
+    private lateinit var underTest: NoteTaskIntentResolver
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        resolver = NoteTaskIntentResolver(packageManager)
-    }
-
-    private fun createResolveInfo(
-        activityInfo: ActivityInfo? = createActivityInfo(),
-    ): ResolveInfo {
-        return ResolveInfo().apply { this.activityInfo = activityInfo }
-    }
-
-    private fun createActivityInfo(
-        packageName: String = "PackageName",
-        name: String? = "ActivityName",
-        exported: Boolean = true,
-        enabled: Boolean = true,
-        showWhenLocked: Boolean = true,
-        turnScreenOn: Boolean = true,
-    ): ActivityInfo {
-        return ActivityInfo().apply {
-            this.name = name
-            this.exported = exported
-            this.enabled = enabled
-            if (showWhenLocked) {
-                flags = flags or ActivityInfo.FLAG_SHOW_WHEN_LOCKED
-            }
-            if (turnScreenOn) {
-                flags = flags or ActivityInfo.FLAG_TURN_SCREEN_ON
-            }
-            this.applicationInfo = ApplicationInfo().apply { this.packageName = packageName }
-        }
-    }
-
-    private fun givenQueryIntentActivities(block: () -> List<ResolveInfo>) {
-        whenever(packageManager.queryIntentActivities(any(), any<ResolveInfoFlags>()))
-            .thenReturn(block())
-    }
-
-    private fun givenResolveActivity(block: () -> ResolveInfo?) {
-        whenever(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenReturn(block())
+        underTest = NoteTaskIntentResolver(context, roleManager)
     }
 
     @Test
-    fun resolveIntent_shouldReturnNotesIntent() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo()) }
+    fun resolveIntent_shouldReturnIntentInStylusMode() {
+        val packageName = "com.android.note.app"
+        whenever(roleManager.getRoleHoldersAsUser(NoteTaskIntentResolver.ROLE_NOTES, context.user))
+            .then { listOf(packageName) }
 
-        val actual = resolver.resolveIntent()
+        val actual = underTest.resolveIntent()
 
-        val expected =
-            Intent(ACTION_CREATE_NOTE)
-                .setPackage("PackageName")
-                .setComponent(ComponentName("PackageName", "ActivityName"))
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        // Compares the string representation of both intents, as they are different instances.
-        assertThat(actual.toString()).isEqualTo(expected.toString())
+        requireNotNull(actual) { "Intent must not be null" }
+        assertThat(actual.action).isEqualTo(ACTION_CREATE_NOTE)
+        assertThat(actual.`package`).isEqualTo(packageName)
+        val expectedExtra = actual.getExtra(NoteTaskIntentResolver.INTENT_EXTRA_USE_STYLUS_MODE)
+        assertThat(expectedExtra).isEqualTo(true)
+        val expectedFlag = actual.flags and Intent.FLAG_ACTIVITY_NEW_TASK
+        assertThat(expectedFlag).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
     }
 
     @Test
-    fun resolveIntent_activityInfoEnabledIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(enabled = false))
-        }
+    fun resolveIntent_noRoleHolderIsSet_shouldReturnNull() {
+        whenever(roleManager.getRoleHoldersAsUser(eq(NoteTaskIntentResolver.ROLE_NOTES), any()))
+            .then { listOf<String>() }
 
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoExportedIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(exported = false))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoShowWhenLockedIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(showWhenLocked = false))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoTurnScreenOnIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(turnScreenOn = false))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoNameIsBlank_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo(name = "")) }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoNameIsNull_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo(name = null)) }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoIsNull_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = null) }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_resolveActivityIsNull_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { null }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_packageNameIsBlank_shouldReturnNull() {
-        givenQueryIntentActivities {
-            listOf(createResolveInfo(createActivityInfo(packageName = "")))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityNotFoundForAction_shouldReturnNull() {
-        givenQueryIntentActivities { emptyList() }
-
-        val actual = resolver.resolveIntent()
+        val actual = underTest.resolveIntent()
 
         assertThat(actual).isNull()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 5124eb9..e6f272b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -37,6 +37,7 @@
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
+import org.mockito.Mockito
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
@@ -152,4 +153,18 @@
         // and cause us to drop a frame during the LOCKSCREEN_TRANSITION_FROM_AOD CUJ.
         assertEquals(0.99f, controller.dozeAmount, 0.009f)
     }
+
+    @Test
+    fun testSetDreamState_invokesCallback() {
+        val listener = mock(StatusBarStateController.StateListener::class.java)
+        controller.addCallback(listener)
+
+        controller.setIsDreaming(true)
+        verify(listener).onDreamingChanged(true)
+
+        Mockito.clearInvocations(listener)
+
+        controller.setIsDreaming(false)
+        verify(listener).onDreamingChanged(false)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 43b6e41..cd6778e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -33,6 +33,7 @@
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.BcSmartspaceConfigPlugin
@@ -118,6 +119,9 @@
     private lateinit var configPlugin: BcSmartspaceConfigPlugin
 
     @Mock
+    private lateinit var dumpManager: DumpManager
+
+    @Mock
     private lateinit var controllerListener: SmartspaceTargetListener
 
     @Captor
@@ -206,6 +210,7 @@
                 statusBarStateController,
                 deviceProvisionedController,
                 keyguardBypassController,
+                dumpManager,
                 execution,
                 executor,
                 bgExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
deleted file mode 100644
index 2f49535..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-
-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.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.hardware.biometrics.BiometricSourceType;
-import android.os.Handler;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardSecurityModel;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
-import com.android.systemui.DejankUtils;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class KeyguardBouncerTest extends SysuiTestCase {
-
-    @Mock
-    private FalsingCollector mFalsingCollector;
-    @Mock
-    private ViewMediatorCallback mViewMediatorCallback;
-    @Mock
-    private DismissCallbackRegistry mDismissCallbackRegistry;
-    @Mock
-    private KeyguardHostViewController mKeyguardHostViewController;
-    @Mock
-    private PrimaryBouncerExpansionCallback mExpansionCallback;
-    @Mock
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock
-    private KeyguardStateController mKeyguardStateController;
-    @Mock
-    private KeyguardBypassController mKeyguardBypassController;
-    @Mock
-    private Handler mHandler;
-    @Mock
-    private KeyguardSecurityModel mKeyguardSecurityModel;
-    @Mock
-    private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
-    @Mock
-    private KeyguardBouncerComponent mKeyguardBouncerComponent;
-    private ViewGroup mContainer;
-    @Rule
-    public MockitoRule mRule = MockitoJUnit.rule();
-    private Integer mRootVisibility = View.INVISIBLE;
-    private KeyguardBouncer mBouncer;
-
-    @Before
-    public void setup() {
-        allowTestableLooperAsMainThread();
-        when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
-                .thenReturn(KeyguardSecurityModel.SecurityMode.None);
-        DejankUtils.setImmediate(true);
-
-        mContainer = spy(new FrameLayout(getContext()));
-        when(mKeyguardBouncerComponentFactory.create(mContainer)).thenReturn(
-                mKeyguardBouncerComponent);
-        when(mKeyguardBouncerComponent.getKeyguardHostViewController())
-                .thenReturn(mKeyguardHostViewController);
-
-        mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
-                mDismissCallbackRegistry, mFalsingCollector,
-                mKeyguardStateController, mKeyguardUpdateMonitor,
-                mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
-                mKeyguardBouncerComponentFactory)
-                .create(mContainer, mExpansionCallback);
-    }
-
-    @Test
-    public void testInflateView_doesntCrash() {
-        mBouncer.inflateView();
-    }
-
-    @Test
-    public void testShow_notifiesFalsingManager() {
-        mBouncer.show(true);
-        verify(mFalsingCollector).onBouncerShown();
-
-        mBouncer.show(true, false);
-        verifyNoMoreInteractions(mFalsingCollector);
-    }
-
-    /**
-     * Regression test: Invisible bouncer when occluded.
-     */
-    @Test
-    public void testShow_bouncerIsVisible() {
-        // Expand notification panel as if we were in the keyguard.
-        mBouncer.ensureView();
-        mBouncer.setExpansion(1);
-
-        reset(mKeyguardHostViewController);
-
-        mBouncer.show(true);
-        verify(mKeyguardHostViewController).setExpansion(0);
-    }
-
-    @Test
-    public void testShow_notifiesVisibility() {
-        mBouncer.show(true);
-        verify(mKeyguardStateController).notifyBouncerShowing(eq(true));
-        verify(mExpansionCallback).onStartingToShow();
-
-        // Not called again when visible
-        reset(mViewMediatorCallback);
-        mBouncer.show(true);
-        verifyNoMoreInteractions(mViewMediatorCallback);
-    }
-
-    @Test
-    public void testShow_triesToDismissKeyguard() {
-        mBouncer.show(true);
-        verify(mKeyguardHostViewController).dismiss(anyInt());
-    }
-
-    @Test
-    public void testShow_resetsSecuritySelection() {
-        mBouncer.show(false);
-        verify(mKeyguardHostViewController, never()).showPrimarySecurityScreen();
-
-        mBouncer.hide(false);
-        mBouncer.show(true);
-        verify(mKeyguardHostViewController).showPrimarySecurityScreen();
-    }
-
-    @Test
-    public void testShow_animatesKeyguardView() {
-        mBouncer.show(true);
-        verify(mKeyguardHostViewController).appear(anyInt());
-    }
-
-    @Test
-    public void testShow_showsErrorMessage() {
-        final String errorMessage = "an error message";
-        when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage);
-        mBouncer.show(true);
-        verify(mKeyguardHostViewController).showErrorMessage(eq(errorMessage));
-    }
-
-    @Test
-    public void testSetExpansion_notifiesFalsingManager() {
-        mBouncer.ensureView();
-        mBouncer.setExpansion(0.5f);
-
-        mBouncer.setExpansion(EXPANSION_HIDDEN);
-        verify(mFalsingCollector).onBouncerHidden();
-        verify(mExpansionCallback).onFullyHidden();
-
-        mBouncer.setExpansion(EXPANSION_VISIBLE);
-        verify(mFalsingCollector).onBouncerShown();
-        verify(mExpansionCallback).onFullyShown();
-
-        verify(mExpansionCallback, never()).onStartingToHide();
-        verify(mKeyguardHostViewController, never()).onStartingToHide();
-        mBouncer.setExpansion(0.9f);
-        verify(mExpansionCallback).onStartingToHide();
-        verify(mKeyguardHostViewController).onStartingToHide();
-    }
-
-    @Test
-    public void testSetExpansion_notifiesKeyguardView() {
-        mBouncer.ensureView();
-        mBouncer.setExpansion(0.1f);
-
-        mBouncer.setExpansion(0);
-        verify(mKeyguardHostViewController).onResume();
-        verify(mContainer).announceForAccessibility(any());
-    }
-
-    @Test
-    public void show_notifiesKeyguardViewController() {
-        mBouncer.ensureView();
-
-        mBouncer.show(/* resetSecuritySelection= */ false);
-
-        verify(mKeyguardHostViewController).onBouncerVisibilityChanged(View.VISIBLE);
-    }
-
-    @Test
-    public void testHide_notifiesFalsingManager() {
-        mBouncer.hide(false);
-        verify(mFalsingCollector).onBouncerHidden();
-    }
-
-    @Test
-    public void testHide_notifiesVisibility() {
-        mBouncer.hide(false);
-        verify(mKeyguardStateController).notifyBouncerShowing(eq(false));
-    }
-
-    @Test
-    public void testHide_notifiesDismissCallbackIfVisible() {
-        mBouncer.hide(false);
-        verifyZeroInteractions(mDismissCallbackRegistry);
-        mBouncer.show(false);
-        mBouncer.hide(false);
-        verify(mDismissCallbackRegistry).notifyDismissCancelled();
-    }
-
-    @Test
-    public void testHide_notShowingAnymore() {
-        mBouncer.ensureView();
-        mBouncer.show(false /* resetSecuritySelection */);
-        mBouncer.hide(false /* destroyViews */);
-        Assert.assertFalse("Not showing", mBouncer.isShowing());
-    }
-
-    @Test
-    public void testShowPromptReason_propagates() {
-        mBouncer.ensureView();
-        mBouncer.showPromptReason(1);
-        verify(mKeyguardHostViewController).showPromptReason(eq(1));
-    }
-
-    @Test
-    public void testShowMessage_propagates() {
-        final String message = "a message";
-        mBouncer.ensureView();
-        mBouncer.showMessage(message, ColorStateList.valueOf(Color.GREEN));
-        verify(mKeyguardHostViewController).showMessage(
-                eq(message), eq(ColorStateList.valueOf(Color.GREEN)));
-    }
-
-    @Test
-    public void testShowOnDismissAction_showsBouncer() {
-        final OnDismissAction dismissAction = () -> false;
-        final Runnable cancelAction = () -> {};
-        mBouncer.showWithDismissAction(dismissAction, cancelAction);
-        verify(mKeyguardHostViewController).setOnDismissAction(dismissAction, cancelAction);
-        Assert.assertTrue("Should be showing", mBouncer.isShowing());
-    }
-
-    @Test
-    public void testStartPreHideAnimation_notifiesView() {
-        final boolean[] ran = {false};
-        final Runnable r = () -> ran[0] = true;
-        mBouncer.startPreHideAnimation(r);
-        Assert.assertTrue("Callback should have been invoked", ran[0]);
-
-        ran[0] = false;
-        mBouncer.ensureView();
-        mBouncer.startPreHideAnimation(r);
-        verify(mKeyguardHostViewController).startDisappearAnimation(r);
-        Assert.assertFalse("Callback should have been deferred", ran[0]);
-    }
-
-    @Test
-    public void testIsShowing_animated() {
-        Assert.assertFalse("Show wasn't invoked yet", mBouncer.isShowing());
-        mBouncer.show(true /* reset */);
-        Assert.assertTrue("Should be showing", mBouncer.isShowing());
-    }
-
-    @Test
-    public void testIsShowing_forSwipeUp() {
-        mBouncer.setExpansion(1f);
-        mBouncer.show(true /* reset */, false /* animated */);
-        Assert.assertFalse("Should only be showing after collapsing notification panel",
-                mBouncer.isShowing());
-        mBouncer.setExpansion(0f);
-        Assert.assertTrue("Should be showing", mBouncer.isShowing());
-    }
-
-    @Test
-    public void testSetExpansion() {
-        mBouncer.ensureView();
-        mBouncer.setExpansion(0.5f);
-        verify(mKeyguardHostViewController).setExpansion(0.5f);
-    }
-
-    @Test
-    public void testIsFullscreenBouncer_asksKeyguardView() {
-        mBouncer.ensureView();
-        mBouncer.isFullscreenBouncer();
-        verify(mKeyguardHostViewController).getCurrentSecurityMode();
-    }
-
-    @Test
-    public void testIsHiding_preHideOrHide() {
-        Assert.assertFalse("Should not be hiding on initial state", mBouncer.isAnimatingAway());
-        mBouncer.startPreHideAnimation(null /* runnable */);
-        Assert.assertTrue("Should be hiding during pre-hide", mBouncer.isAnimatingAway());
-        mBouncer.hide(false /* destroyView */);
-        Assert.assertFalse("Should be hidden after hide()", mBouncer.isAnimatingAway());
-    }
-
-    @Test
-    public void testIsHiding_skipsTranslation() {
-        mBouncer.show(false /* reset */);
-        reset(mKeyguardHostViewController);
-        mBouncer.startPreHideAnimation(null /* runnable */);
-        mBouncer.setExpansion(0.5f);
-        verify(mKeyguardHostViewController, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void testIsSecure() {
-        mBouncer.ensureView();
-        for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){
-            reset(mKeyguardSecurityModel);
-            when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(mode);
-            Assert.assertEquals("Security doesn't match for mode: " + mode,
-                    mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None);
-        }
-    }
-
-    @Test
-    public void testIsShowingScrimmed_true() {
-        doAnswer(invocation -> {
-            assertThat(mBouncer.isScrimmed()).isTrue();
-            return null;
-        }).when(mExpansionCallback).onFullyShown();
-        mBouncer.show(false /* resetSecuritySelection */, true /* animate */);
-        assertThat(mBouncer.isScrimmed()).isTrue();
-        mBouncer.hide(false /* destroyView */);
-        assertThat(mBouncer.isScrimmed()).isFalse();
-    }
-
-    @Test
-    public void testIsShowingScrimmed_false() {
-        doAnswer(invocation -> {
-            assertThat(mBouncer.isScrimmed()).isFalse();
-            return null;
-        }).when(mExpansionCallback).onFullyShown();
-        mBouncer.show(false /* resetSecuritySelection */, false /* animate */);
-        assertThat(mBouncer.isScrimmed()).isFalse();
-    }
-
-    @Test
-    public void testWillDismissWithAction() {
-        mBouncer.ensureView();
-        Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction());
-        when(mKeyguardHostViewController.hasDismissActions()).thenReturn(true);
-        Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction());
-    }
-
-    @Test
-    public void testShow_delaysIfFaceAuthIsRunning() {
-        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
-                .thenReturn(true);
-        when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
-        mBouncer.show(true /* reset */);
-
-        ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
-        verify(mHandler).postDelayed(showRunnable.capture(),
-                eq(KeyguardBouncer.BOUNCER_FACE_DELAY));
-
-        mBouncer.hide(false /* destroyView */);
-        verify(mHandler).removeCallbacks(eq(showRunnable.getValue()));
-    }
-
-    @Test
-    public void testShow_doesNotDelaysIfFaceAuthIsNotAllowed() {
-        when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
-        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
-                .thenReturn(false);
-        mBouncer.show(true /* reset */);
-
-        verify(mHandler, never()).postDelayed(any(), anyLong());
-    }
-
-    @Test
-    public void testShow_delaysIfFaceAuthIsRunning_unlessBypassEnabled() {
-        when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
-        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
-        mBouncer.show(true /* reset */);
-
-        verify(mHandler, never()).postDelayed(any(), anyLong());
-    }
-
-    @Test
-    public void testShow_delaysIfFaceAuthIsRunning_unlessFingerprintEnrolled() {
-        when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
-        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0))
-                .thenReturn(true);
-        mBouncer.show(true /* reset */);
-
-        verify(mHandler, never()).postDelayed(any(), anyLong());
-    }
-
-    @Test
-    public void testRegisterUpdateMonitorCallback() {
-        verify(mKeyguardUpdateMonitor).registerCallback(any());
-    }
-
-    @Test
-    public void testInTransit_whenTranslation() {
-        mBouncer.show(true);
-        mBouncer.setExpansion(EXPANSION_HIDDEN);
-        assertThat(mBouncer.inTransit()).isFalse();
-        mBouncer.setExpansion(0.5f);
-        assertThat(mBouncer.inTransit()).isTrue();
-        mBouncer.setExpansion(EXPANSION_VISIBLE);
-        assertThat(mBouncer.inTransit()).isFalse();
-    }
-
-    @Test
-    public void testUpdateResources_delegatesToRootView() {
-        mBouncer.ensureView();
-        mBouncer.updateResources();
-
-        // This is mocked, so won't pick up on the call to updateResources via
-        // mKeyguardViewController.init(), only updateResources above.
-        verify(mKeyguardHostViewController).updateResources();
-    }
-
-    @Test
-    public void testUpdateKeyguardPosition_delegatesToRootView() {
-        mBouncer.ensureView();
-        mBouncer.updateKeyguardPosition(1.0f);
-
-        verify(mKeyguardHostViewController).updateKeyguardPosition(1.0f);
-    }
-
-    @Test
-    public void testExpansion_notifiesCallback() {
-        mBouncer.ensureView();
-        mBouncer.setExpansion(0.5f);
-
-        final PrimaryBouncerExpansionCallback callback =
-                mock(PrimaryBouncerExpansionCallback.class);
-        mBouncer.addBouncerExpansionCallback(callback);
-
-        mBouncer.setExpansion(EXPANSION_HIDDEN);
-        verify(callback).onFullyHidden();
-        verify(callback).onExpansionChanged(EXPANSION_HIDDEN);
-
-        Mockito.clearInvocations(callback);
-        mBouncer.setExpansion(EXPANSION_VISIBLE);
-        verify(callback).onFullyShown();
-        verify(callback).onExpansionChanged(EXPANSION_VISIBLE);
-
-        Mockito.clearInvocations(callback);
-        float bouncerHideAmount = 0.9f;
-        // Ensure the callback only triggers once despite multiple calls to setExpansion
-        // with the same value.
-        mBouncer.setExpansion(bouncerHideAmount);
-        mBouncer.setExpansion(bouncerHideAmount);
-        verify(callback, times(1)).onStartingToHide();
-        verify(callback, times(1)).onExpansionChanged(bouncerHideAmount);
-
-        Mockito.clearInvocations(callback);
-        mBouncer.removeBouncerExpansionCallback(callback);
-        bouncerHideAmount = 0.5f;
-        mBouncer.setExpansion(bouncerHideAmount);
-        verify(callback, never()).onExpansionChanged(bouncerHideAmount);
-    }
-
-    @Test
-    public void testOnResumeCalledForFullscreenBouncerOnSecondShow() {
-        // GIVEN a security mode which requires fullscreen bouncer
-        when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
-                .thenReturn(KeyguardSecurityModel.SecurityMode.SimPin);
-        mBouncer.show(true);
-
-        // WHEN a second call to show occurs, the bouncer will already by visible
-        reset(mKeyguardHostViewController);
-        mBouncer.show(true);
-
-        // THEN ensure the ViewController is told to resume
-        verify(mKeyguardHostViewController).onResume();
-    }
-}
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 1ba0a36..d8446f4 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
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.flags.Flags.MODERN_BOUNCER;
 import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
 import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
 
@@ -109,7 +108,6 @@
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private View mNotificationContainer;
     @Mock private KeyguardBypassController mBypassController;
-    @Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory;
     @Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
     @Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
     @Mock private KeyguardMessageArea mKeyguardMessageArea;
@@ -153,8 +151,6 @@
                 .isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM))
                 .thenReturn(true);
 
-        when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(true);
-
         mStatusBarKeyguardViewManager =
                 new StatusBarKeyguardViewManager(
                         getContext(),
@@ -169,7 +165,6 @@
                         mock(NotificationShadeWindowController.class),
                         mKeyguardStateController,
                         mock(NotificationMediaManager.class),
-                        mKeyguardBouncerFactory,
                         mKeyguardMessageAreaFactory,
                         Optional.of(mSysUiUnfoldComponent),
                         () -> mShadeController,
@@ -660,7 +655,6 @@
                         mock(NotificationShadeWindowController.class),
                         mKeyguardStateController,
                         mock(NotificationMediaManager.class),
-                        mKeyguardBouncerFactory,
                         mKeyguardMessageAreaFactory,
                         Optional.of(mSysUiUnfoldComponent),
                         () -> mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
deleted file mode 100644
index 55ab681..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.flags.Flags.MODERN_BOUNCER;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewRootImpl;
-import android.window.OnBackInvokedCallback;
-import android.window.OnBackInvokedDispatcher;
-import android.window.WindowOnBackInvokedDispatcher;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardMessageArea;
-import com.android.keyguard.KeyguardMessageAreaController;
-import com.android.keyguard.KeyguardSecurityModel;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.keyguard.data.BouncerView;
-import com.android.systemui.keyguard.data.BouncerViewDelegate;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.shade.NotificationPanelViewController;
-import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.ShadeExpansionChangeEvent;
-import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
-
-import com.google.common.truth.Truth;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-/**
- * StatusBarKeyguardViewManager Test with deprecated KeyguardBouncer.java.
- * TODO: Delete when deleting {@link KeyguardBouncer}
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
-    private static final ShadeExpansionChangeEvent EXPANSION_EVENT =
-            expansionEvent(/* fraction= */ 0.5f, /* expanded= */ false, /* tracking= */ true);
-
-    @Mock private ViewMediatorCallback mViewMediatorCallback;
-    @Mock private LockPatternUtils mLockPatternUtils;
-    @Mock private CentralSurfaces mCentralSurfaces;
-    @Mock private ViewGroup mContainer;
-    @Mock private NotificationPanelViewController mNotificationPanelView;
-    @Mock private BiometricUnlockController mBiometricUnlockController;
-    @Mock private SysuiStatusBarStateController mStatusBarStateController;
-    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock private View mNotificationContainer;
-    @Mock private KeyguardBypassController mBypassController;
-    @Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory;
-    @Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
-    @Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
-    @Mock private KeyguardBouncer mPrimaryBouncer;
-    @Mock private KeyguardMessageArea mKeyguardMessageArea;
-    @Mock private ShadeController mShadeController;
-    @Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;
-    @Mock private DreamOverlayStateController mDreamOverlayStateController;
-    @Mock private LatencyTracker mLatencyTracker;
-    @Mock private FeatureFlags mFeatureFlags;
-    @Mock private KeyguardSecurityModel mKeyguardSecurityModel;
-    @Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
-    @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
-    @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
-    @Mock private BouncerView mBouncerView;
-    @Mock private BouncerViewDelegate mBouncerViewDelegate;
-
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
-            mBouncerExpansionCallback;
-    private FakeKeyguardStateController mKeyguardStateController =
-            spy(new FakeKeyguardStateController());
-
-    @Mock private ViewRootImpl mViewRootImpl;
-    @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
-    @Captor
-    private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
-
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        when(mKeyguardBouncerFactory.create(
-                any(ViewGroup.class),
-                any(PrimaryBouncerExpansionCallback.class)))
-                .thenReturn(mPrimaryBouncer);
-        when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer);
-        when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
-        when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
-                .thenReturn(mKeyguardMessageAreaController);
-        when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
-
-        mStatusBarKeyguardViewManager =
-                new StatusBarKeyguardViewManager(
-                        getContext(),
-                        mViewMediatorCallback,
-                        mLockPatternUtils,
-                        mStatusBarStateController,
-                        mock(ConfigurationController.class),
-                        mKeyguardUpdateMonitor,
-                        mDreamOverlayStateController,
-                        mock(NavigationModeController.class),
-                        mock(DockManager.class),
-                        mock(NotificationShadeWindowController.class),
-                        mKeyguardStateController,
-                        mock(NotificationMediaManager.class),
-                        mKeyguardBouncerFactory,
-                        mKeyguardMessageAreaFactory,
-                        Optional.of(mSysUiUnfoldComponent),
-                        () -> mShadeController,
-                        mLatencyTracker,
-                        mKeyguardSecurityModel,
-                        mFeatureFlags,
-                        mPrimaryBouncerCallbackInteractor,
-                        mPrimaryBouncerInteractor,
-                        mBouncerView,
-                        mAlternateBouncerInteractor) {
-                    @Override
-                    public ViewRootImpl getViewRootImpl() {
-                        return mViewRootImpl;
-                    }
-                };
-        when(mViewRootImpl.getOnBackInvokedDispatcher())
-                .thenReturn(mOnBackInvokedDispatcher);
-        mStatusBarKeyguardViewManager.registerCentralSurfaces(
-                mCentralSurfaces,
-                mNotificationPanelView,
-                new ShadeExpansionStateManager(),
-                mBiometricUnlockController,
-                mNotificationContainer,
-                mBypassController);
-        mStatusBarKeyguardViewManager.show(null);
-        ArgumentCaptor<PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
-                ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
-        verify(mKeyguardBouncerFactory).create(any(ViewGroup.class),
-                callbackArgumentCaptor.capture());
-        mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
-    }
-
-    @Test
-    public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
-        OnDismissAction action = () -> false;
-        Runnable cancelAction = () -> {};
-        mStatusBarKeyguardViewManager.dismissWithAction(
-                action, cancelAction, false /* afterKeyguardGone */);
-        verify(mPrimaryBouncer).showWithDismissAction(eq(action), eq(cancelAction));
-    }
-
-    @Test
-    public void showBouncer_onlyWhenShowing() {
-        mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
-        mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
-        verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean());
-        verify(mPrimaryBouncer, never()).show(anyBoolean());
-    }
-
-    @Test
-    public void showBouncer_notWhenBouncerAlreadyShowing() {
-        mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
-        when(mPrimaryBouncer.isSecure()).thenReturn(true);
-        mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
-        verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean());
-        verify(mPrimaryBouncer, never()).show(anyBoolean());
-    }
-
-    @Test
-    public void showBouncer_showsTheBouncer() {
-        mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
-        verify(mPrimaryBouncer).show(anyBoolean(), eq(true));
-    }
-
-    @Test
-    public void onPanelExpansionChanged_neverShowsDuringHintAnimation() {
-        when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void onPanelExpansionChanged_propagatesToBouncerOnlyIfShowing() {
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f));
-
-        when(mPrimaryBouncer.isShowing()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                expansionEvent(/* fraction= */ 0.6f, /* expanded= */ false, /* tracking= */ true));
-        verify(mPrimaryBouncer).setExpansion(eq(0.6f));
-    }
-
-    @Test
-    public void onPanelExpansionChanged_duplicateEventsAreIgnored() {
-        when(mPrimaryBouncer.isShowing()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer).setExpansion(eq(0.5f));
-
-        reset(mPrimaryBouncer);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f));
-    }
-
-    @Test
-    public void onPanelExpansionChanged_hideBouncer_afterKeyguardHidden() {
-        mStatusBarKeyguardViewManager.hide(0, 0);
-        when(mPrimaryBouncer.inTransit()).thenReturn(true);
-
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer).setExpansion(eq(EXPANSION_HIDDEN));
-    }
-
-    @Test
-    public void onPanelExpansionChanged_showsBouncerWhenSwiping() {
-        mKeyguardStateController.setCanDismissLockScreen(false);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer).show(eq(false), eq(false));
-
-        // But not when it's already visible
-        reset(mPrimaryBouncer);
-        when(mPrimaryBouncer.isShowing()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer, never()).show(eq(false), eq(false));
-
-        // Or animating away
-        reset(mPrimaryBouncer);
-        when(mPrimaryBouncer.isAnimatingAway()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer, never()).show(eq(false), eq(false));
-    }
-
-    @Test
-    public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() {
-        when(mBiometricUnlockController.getMode())
-                .thenReturn(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                expansionEvent(
-                        /* fraction= */ EXPANSION_VISIBLE,
-                        /* expanded= */ true,
-                        /* tracking= */ false));
-        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void onPanelExpansionChanged_neverTranslatesBouncerWhenDismissBouncer() {
-        // Since KeyguardBouncer.EXPANSION_VISIBLE = 0 panel expansion, if the unlock is dismissing
-        // the bouncer, there may be an onPanelExpansionChanged(0) call to collapse the panel
-        // which would mistakenly cause the bouncer to show briefly before its visibility
-        // is set to hide. Therefore, we don't want to propagate panelExpansionChanged to the
-        // bouncer if the bouncer is dismissing as a result of a biometric unlock.
-        when(mBiometricUnlockController.getMode())
-                .thenReturn(BiometricUnlockController.MODE_DISMISS_BOUNCER);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                expansionEvent(
-                        /* fraction= */ EXPANSION_VISIBLE,
-                        /* expanded= */ true,
-                        /* tracking= */ false));
-        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void onPanelExpansionChanged_neverTranslatesBouncerWhenOccluded() {
-        when(mKeyguardStateController.isOccluded()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                expansionEvent(
-                        /* fraction= */ EXPANSION_VISIBLE,
-                        /* expanded= */ true,
-                        /* tracking= */ false));
-        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void onPanelExpansionChanged_neverTranslatesBouncerWhenShowBouncer() {
-        // Since KeyguardBouncer.EXPANSION_VISIBLE = 0 panel expansion, if the unlock is dismissing
-        // the bouncer, there may be an onPanelExpansionChanged(0) call to collapse the panel
-        // which would mistakenly cause the bouncer to show briefly before its visibility
-        // is set to hide. Therefore, we don't want to propagate panelExpansionChanged to the
-        // bouncer if the bouncer is dismissing as a result of a biometric unlock.
-        when(mBiometricUnlockController.getMode())
-                .thenReturn(BiometricUnlockController.MODE_SHOW_BOUNCER);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                expansionEvent(
-                        /* fraction= */ EXPANSION_VISIBLE,
-                        /* expanded= */ true,
-                        /* tracking= */ false));
-        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void onPanelExpansionChanged_neverTranslatesBouncerWhenShadeLocked() {
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                expansionEvent(
-                        /* fraction= */ EXPANSION_VISIBLE,
-                        /* expanded= */ true,
-                        /* tracking= */ false));
-        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
-    }
-
-    @Test
-    public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
-        mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
-        verify(mCentralSurfaces).animateKeyguardUnoccluding();
-
-        when(mPrimaryBouncer.isShowing()).thenReturn(true);
-        clearInvocations(mCentralSurfaces);
-        mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
-        verify(mCentralSurfaces, never()).animateKeyguardUnoccluding();
-    }
-
-    @Test
-    public void setOccluded_onKeyguardOccludedChangedCalled() {
-        clearInvocations(mKeyguardStateController);
-        clearInvocations(mKeyguardUpdateMonitor);
-
-        mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */);
-        verify(mKeyguardStateController).notifyKeyguardState(true, false);
-
-        clearInvocations(mKeyguardUpdateMonitor);
-        clearInvocations(mKeyguardStateController);
-
-        mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
-        verify(mKeyguardStateController).notifyKeyguardState(true, true);
-
-        clearInvocations(mKeyguardUpdateMonitor);
-        clearInvocations(mKeyguardStateController);
-
-        mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */);
-        verify(mKeyguardStateController).notifyKeyguardState(true, false);
-    }
-
-    @Test
-    public void setOccluded_isInLaunchTransition_onKeyguardOccludedChangedCalled() {
-        mStatusBarKeyguardViewManager.show(null);
-
-        mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
-        verify(mKeyguardStateController).notifyKeyguardState(true, true);
-    }
-
-    @Test
-    public void setOccluded_isLaunchingActivityOverLockscreen_onKeyguardOccludedChangedCalled() {
-        when(mCentralSurfaces.isLaunchingActivityOverLockscreen()).thenReturn(true);
-        mStatusBarKeyguardViewManager.show(null);
-
-        mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
-        verify(mKeyguardStateController).notifyKeyguardState(true, true);
-    }
-
-    @Test
-    public void testHiding_cancelsGoneRunnable() {
-        OnDismissAction action = mock(OnDismissAction.class);
-        Runnable cancelAction = mock(Runnable.class);
-        mStatusBarKeyguardViewManager.dismissWithAction(
-                action, cancelAction, true /* afterKeyguardGone */);
-
-        when(mPrimaryBouncer.isShowing()).thenReturn(false);
-        mStatusBarKeyguardViewManager.hideBouncer(true);
-        mStatusBarKeyguardViewManager.hide(0, 30);
-        verify(action, never()).onDismiss();
-        verify(cancelAction).run();
-    }
-
-    @Test
-    public void testHidingBouncer_cancelsGoneRunnable() {
-        OnDismissAction action = mock(OnDismissAction.class);
-        Runnable cancelAction = mock(Runnable.class);
-        mStatusBarKeyguardViewManager.dismissWithAction(
-                action, cancelAction, true /* afterKeyguardGone */);
-
-        when(mPrimaryBouncer.isShowing()).thenReturn(false);
-        mStatusBarKeyguardViewManager.hideBouncer(true);
-
-        verify(action, never()).onDismiss();
-        verify(cancelAction).run();
-    }
-
-    @Test
-    public void testHiding_doesntCancelWhenShowing() {
-        OnDismissAction action = mock(OnDismissAction.class);
-        Runnable cancelAction = mock(Runnable.class);
-        mStatusBarKeyguardViewManager.dismissWithAction(
-                action, cancelAction, true /* afterKeyguardGone */);
-
-        mStatusBarKeyguardViewManager.hide(0, 30);
-        verify(action).onDismiss();
-        verify(cancelAction, never()).run();
-    }
-
-    @Test
-    public void testBouncerIsOrWillBeShowing_whenBouncerIsInTransit() {
-        when(mPrimaryBouncer.isShowing()).thenReturn(false);
-        when(mPrimaryBouncer.inTransit()).thenReturn(true);
-
-        assertTrue(
-                "Is or will be showing should be true when bouncer is in transit",
-                mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing());
-    }
-
-    @Test
-    public void testUpdateResources_delegatesToBouncer() {
-        mStatusBarKeyguardViewManager.updateResources();
-
-        verify(mPrimaryBouncer).updateResources();
-    }
-
-    @Test
-    public void updateKeyguardPosition_delegatesToBouncer() {
-        mStatusBarKeyguardViewManager.updateKeyguardPosition(1.0f);
-
-        verify(mPrimaryBouncer).updateKeyguardPosition(1.0f);
-    }
-
-    @Test
-    public void testIsBouncerInTransit() {
-        when(mPrimaryBouncer.inTransit()).thenReturn(true);
-        Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isTrue();
-        when(mPrimaryBouncer.inTransit()).thenReturn(false);
-        Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isFalse();
-        mPrimaryBouncer = null;
-        Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isFalse();
-    }
-
-    private static ShadeExpansionChangeEvent expansionEvent(
-            float fraction, boolean expanded, boolean tracking) {
-        return new ShadeExpansionChangeEvent(
-                fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
-    }
-
-    @Test
-    public void testPredictiveBackCallback_registration() {
-        /* verify that a predictive back callback is registered when the bouncer becomes visible */
-        mBouncerExpansionCallback.onVisibilityChanged(true);
-        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
-                mOnBackInvokedCallback.capture());
-
-        /* verify that the same callback is unregistered when the bouncer becomes invisible */
-        mBouncerExpansionCallback.onVisibilityChanged(false);
-        verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
-                eq(mOnBackInvokedCallback.getValue()));
-    }
-
-    @Test
-    public void testPredictiveBackCallback_invocationHidesBouncer() {
-        mBouncerExpansionCallback.onVisibilityChanged(true);
-        /* capture the predictive back callback during registration */
-        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
-                mOnBackInvokedCallback.capture());
-
-        when(mPrimaryBouncer.isShowing()).thenReturn(true);
-        when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
-        /* invoke the back callback directly */
-        mOnBackInvokedCallback.getValue().onBackInvoked();
-
-        /* verify that the bouncer will be hidden as a result of the invocation */
-        verify(mCentralSurfaces).setBouncerShowing(eq(false));
-    }
-
-    @Test
-    public void testReportBouncerOnDreamWhenVisible() {
-        mBouncerExpansionCallback.onVisibilityChanged(true);
-        verify(mCentralSurfaces).setBouncerShowingOverDream(false);
-        Mockito.clearInvocations(mCentralSurfaces);
-        when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
-        mBouncerExpansionCallback.onVisibilityChanged(true);
-        verify(mCentralSurfaces).setBouncerShowingOverDream(true);
-    }
-
-    @Test
-    public void testReportBouncerOnDreamWhenNotVisible() {
-        mBouncerExpansionCallback.onVisibilityChanged(false);
-        verify(mCentralSurfaces).setBouncerShowingOverDream(false);
-        Mockito.clearInvocations(mCentralSurfaces);
-        when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
-        mBouncerExpansionCallback.onVisibilityChanged(false);
-        verify(mCentralSurfaces).setBouncerShowingOverDream(false);
-    }
-
-    @Test
-    public void flag_off_DoesNotCallBouncerInteractor() {
-        when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(false);
-        mStatusBarKeyguardViewManager.hideBouncer(false);
-        verify(mPrimaryBouncerInteractor, never()).hide();
-    }
-
-    @Test
-    public void hideAlternateBouncer_beforeCentralSurfacesRegistered() {
-        mStatusBarKeyguardViewManager =
-                new StatusBarKeyguardViewManager(
-                        getContext(),
-                        mViewMediatorCallback,
-                        mLockPatternUtils,
-                        mStatusBarStateController,
-                        mock(ConfigurationController.class),
-                        mKeyguardUpdateMonitor,
-                        mDreamOverlayStateController,
-                        mock(NavigationModeController.class),
-                        mock(DockManager.class),
-                        mock(NotificationShadeWindowController.class),
-                        mKeyguardStateController,
-                        mock(NotificationMediaManager.class),
-                        mKeyguardBouncerFactory,
-                        mKeyguardMessageAreaFactory,
-                        Optional.of(mSysUiUnfoldComponent),
-                        () -> mShadeController,
-                        mLatencyTracker,
-                        mKeyguardSecurityModel,
-                        mFeatureFlags,
-                        mPrimaryBouncerCallbackInteractor,
-                        mPrimaryBouncerInteractor,
-                        mBouncerView,
-                        mAlternateBouncerInteractor) {
-                    @Override
-                    public ViewRootImpl getViewRootImpl() {
-                        return mViewRootImpl;
-                    }
-                };
-
-        // the following call before registering centralSurfaces should NOT throw a NPE:
-        mStatusBarKeyguardViewManager.hideAlternateBouncer(true);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
index b32058f..3dccbbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
@@ -45,7 +45,7 @@
 
     @Test
     fun testLogNetworkCapsChange_bufferHasInfo() {
-        logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS)
+        logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
 
         val stringWriter = StringWriter()
         buffer.dump(PrintWriter(stringWriter), tailLength = 0)
@@ -54,6 +54,7 @@
         val expectedNetId = NET_1_ID.toString()
         val expectedCaps = NET_1_CAPS.toString()
 
+        assertThat(actualString).contains("true")
         assertThat(actualString).contains(expectedNetId)
         assertThat(actualString).contains(expectedCaps)
     }
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 87ce8fa..7099f1f 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
@@ -21,7 +21,10 @@
 import android.net.NetworkCapabilities
 import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_VPN
 import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.TransportInfo
+import android.net.VpnTransportInfo
 import android.net.vcn.VcnTransportInfo
 import android.net.wifi.WifiInfo
 import android.net.wifi.WifiManager
@@ -243,6 +246,54 @@
         job.cancel()
     }
 
+    /** Regression test for b/266628069. */
+    @Test
+    fun isWifiDefault_transportInfoIsNotWifi_andNoWifiTransport_false() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isWifiDefault.launchIn(this)
+
+            val transportInfo = VpnTransportInfo(
+                /* type= */ 0,
+                /* sessionId= */ "sessionId",
+            )
+            val networkCapabilities = mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
+                whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+                whenever(it.transportInfo).thenReturn(transportInfo)
+            }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
+
+            assertThat(underTest.isWifiDefault.value).isFalse()
+
+            job.cancel()
+        }
+
+    /** Regression test for b/266628069. */
+    @Test
+    fun isWifiDefault_transportInfoIsNotWifi_butHasWifiTransport_true() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isWifiDefault.launchIn(this)
+
+            val transportInfo = VpnTransportInfo(
+                /* type= */ 0,
+                /* sessionId= */ "sessionId",
+            )
+            val networkCapabilities = mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+                whenever(it.transportInfo).thenReturn(transportInfo)
+            }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
+
+            assertThat(underTest.isWifiDefault.value).isTrue()
+
+            job.cancel()
+        }
+
     @Test
     fun isWifiDefault_cellularVcnNetwork_isTrue() = runBlocking(IMMEDIATE) {
         val job = underTest.isWifiDefault.launchIn(this)
@@ -260,6 +311,24 @@
     }
 
     @Test
+    fun wifiNetwork_cellularAndWifiTransports_usesCellular_isTrue() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isWifiDefault.launchIn(this)
+
+            val capabilities = mock<NetworkCapabilities>().apply {
+                whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+            }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+            assertThat(underTest.isWifiDefault.value).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
     fun isWifiDefault_cellularNotVcnNetwork_isFalse() = runBlocking(IMMEDIATE) {
         val job = underTest.isWifiDefault.launchIn(this)
 
@@ -467,6 +536,28 @@
         job.cancel()
     }
 
+    /** Regression test for b/266628069. */
+    @Test
+    fun wifiNetwork_transportInfoIsNotWifi_flowHasNoNetwork() =
+        runBlocking(IMMEDIATE) {
+            var latest: WifiNetworkModel? = null
+            val job = underTest
+                .wifiNetwork
+                .onEach { latest = it }
+                .launchIn(this)
+
+            val transportInfo = VpnTransportInfo(
+                /* type= */ 0,
+                /* sessionId= */ "sessionId",
+            )
+            getNetworkCallback()
+                .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(transportInfo))
+
+            assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+            job.cancel()
+        }
+
     @Test
     fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
         var latest: WifiNetworkModel? = null
@@ -535,6 +626,31 @@
     }
 
     @Test
+    fun wifiNetwork_cellularAndWifiTransports_usesCellular() =
+        runBlocking(IMMEDIATE) {
+            var latest: WifiNetworkModel? = null
+            val job = underTest
+                .wifiNetwork
+                .onEach { latest = it }
+                .launchIn(this)
+
+            val capabilities = mock<NetworkCapabilities>().apply {
+                whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+            }
+
+            getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+            assertThat(latest is WifiNetworkModel.Active).isTrue()
+            val latestActive = latest as WifiNetworkModel.Active
+            assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+            assertThat(latestActive.ssid).isEqualTo(SSID)
+
+            job.cancel()
+        }
+
+    @Test
     fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = runBlocking(IMMEDIATE) {
         var latest: WifiNetworkModel? = null
         val job = underTest
@@ -870,12 +986,12 @@
     }
 
     private fun createWifiNetworkCapabilities(
-        wifiInfo: WifiInfo,
+        transportInfo: TransportInfo,
         isValidated: Boolean = true,
     ): NetworkCapabilities {
         return mock<NetworkCapabilities>().also {
             whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-            whenever(it.transportInfo).thenReturn(wifiInfo)
+            whenever(it.transportInfo).thenReturn(transportInfo)
             whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(isValidated)
         }
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
new file mode 100644
index 0000000..5641832
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository {
+    private val _isLockedOut = MutableStateFlow<Boolean>(false)
+    override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow()
+
+    fun setLockedOut(lockedOut: Boolean) {
+        _isLockedOut.value = lockedOut
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 278c98f..0589cfc 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -56,6 +56,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -434,6 +435,48 @@
         return device;
     }
 
+    private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
+            AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+            AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
+            AudioDeviceInfo.TYPE_WIRED_HEADSET,
+            AudioDeviceInfo.TYPE_USB_HEADSET,
+            AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
+            AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+            AudioDeviceInfo.TYPE_HEARING_AID,
+            AudioDeviceInfo.TYPE_BLE_HEADSET,
+            AudioDeviceInfo.TYPE_USB_DEVICE,
+            AudioDeviceInfo.TYPE_BLE_SPEAKER,
+            AudioDeviceInfo.TYPE_LINE_ANALOG,
+            AudioDeviceInfo.TYPE_HDMI,
+            AudioDeviceInfo.TYPE_AUX_LINE
+    };
+
+    /*package */ static boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+        for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
+            if (device.getType() == type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
+        ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
+        AudioDeviceInfo[] allDevices =
+                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
+        for (AudioDeviceInfo device : allDevices) {
+            if (isValidCommunicationDevice(device)) {
+                commDevices.add(device);
+            }
+        }
+        return commDevices;
+    }
+
+    private @Nullable AudioDeviceInfo getCommunicationDeviceOfType(int type) {
+        return getAvailableCommunicationDevices().stream().filter(d -> d.getType() == type)
+                .findFirst().orElse(null);
+    }
+
     /**
      * Returns the device currently requested for communication use case.
      * @return AudioDeviceInfo the requested device for communication.
@@ -441,7 +484,29 @@
     /* package */ AudioDeviceInfo getCommunicationDevice() {
         synchronized (mDeviceStateLock) {
             updateActiveCommunicationDevice();
-            return mActiveCommunicationDevice;
+            AudioDeviceInfo device = mActiveCommunicationDevice;
+            // make sure we return a valid communication device (i.e. a device that is allowed by
+            // setCommunicationDevice()) for consistency.
+            if (device != null) {
+                // a digital dock is used instead of the speaker in speakerphone mode and should
+                // be reflected as such
+                if (device.getType() == AudioDeviceInfo.TYPE_DOCK) {
+                    device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
+                }
+            }
+            // Try to default to earpiece when current communication device is not valid. This can
+            // happen for instance if no call is active. If no earpiece device is available take the
+            // first valid communication device
+            if (device == null || !AudioDeviceBroker.isValidCommunicationDevice(device)) {
+                device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE);
+                if (device == null) {
+                    List<AudioDeviceInfo> commDevices = getAvailableCommunicationDevices();
+                    if (!commDevices.isEmpty()) {
+                        device = commDevices.get(0);
+                    }
+                }
+            }
+            return device;
         }
     }
 
@@ -918,8 +983,8 @@
 
     @GuardedBy("mDeviceStateLock")
     private void dispatchCommunicationDevice() {
-        int portId = (mActiveCommunicationDevice == null) ? 0
-                : mActiveCommunicationDevice.getId();
+        AudioDeviceInfo device = getCommunicationDevice();
+        int portId = device != null ? device.getId() : 0;
         if (portId == mCurCommunicationPortId) {
             return;
         }
@@ -936,6 +1001,7 @@
         mCommDevDispatchers.finishBroadcast();
     }
 
+
     //---------------------------------------------------------------------
     // Communication with (to) AudioService
     //TODO check whether the AudioService methods are candidates to move here
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1bd8f1e..d6ecbc3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5846,46 +5846,16 @@
         restoreDeviceVolumeBehavior();
     }
 
-    private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
-        AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
-        AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
-        AudioDeviceInfo.TYPE_WIRED_HEADSET,
-        AudioDeviceInfo.TYPE_USB_HEADSET,
-        AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
-        AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
-        AudioDeviceInfo.TYPE_HEARING_AID,
-        AudioDeviceInfo.TYPE_BLE_HEADSET,
-        AudioDeviceInfo.TYPE_USB_DEVICE,
-        AudioDeviceInfo.TYPE_BLE_SPEAKER,
-        AudioDeviceInfo.TYPE_LINE_ANALOG,
-        AudioDeviceInfo.TYPE_HDMI,
-        AudioDeviceInfo.TYPE_AUX_LINE
-    };
-
-    private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
-        for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
-            if (device.getType() == type) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /** @see AudioManager#getAvailableCommunicationDevices(int) */
     public int[] getAvailableCommunicationDeviceIds() {
-        ArrayList<Integer> deviceIds = new ArrayList<>();
-        AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
-        for (AudioDeviceInfo device : devices) {
-            if (isValidCommunicationDevice(device)) {
-                deviceIds.add(device.getId());
-            }
-        }
-        return deviceIds.stream().mapToInt(Integer::intValue).toArray();
+        List<AudioDeviceInfo> commDevices = AudioDeviceBroker.getAvailableCommunicationDevices();
+        return commDevices.stream().mapToInt(AudioDeviceInfo::getId).toArray();
     }
-        /**
-         * @see AudioManager#setCommunicationDevice(int)
-         * @see AudioManager#clearCommunicationDevice()
-         */
+
+    /**
+     * @see AudioManager#setCommunicationDevice(int)
+     * @see AudioManager#clearCommunicationDevice()
+     */
     public boolean setCommunicationDevice(IBinder cb, int portId) {
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
@@ -5894,9 +5864,10 @@
         if (portId != 0) {
             device = AudioManager.getDeviceForPortId(portId, AudioManager.GET_DEVICES_OUTPUTS);
             if (device == null) {
-                throw new IllegalArgumentException("invalid portID " + portId);
+                Log.w(TAG, "setCommunicationDevice: invalid portID " + portId);
+                return false;
             }
-            if (!isValidCommunicationDevice(device)) {
+            if (!AudioDeviceBroker.isValidCommunicationDevice(device)) {
                 throw new IllegalArgumentException("invalid device type " + device.getType());
             }
         }
@@ -5939,13 +5910,15 @@
 
     /** @see AudioManager#getCommunicationDevice() */
     public int getCommunicationDevice() {
+        int deviceId = 0;
         final long ident = Binder.clearCallingIdentity();
-        AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
-        Binder.restoreCallingIdentity(ident);
-        if (device == null) {
-            return 0;
+        try {
+            AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
+            deviceId = device != null ? device.getId() : 0;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
-        return device.getId();
+        return deviceId;
     }
 
     /** @see AudioManager#addOnCommunicationDeviceChangedListener(
diff --git a/services/core/java/com/android/server/wm/DeviceStateController.java b/services/core/java/com/android/server/wm/DeviceStateController.java
index a6f8557..2e67399 100644
--- a/services/core/java/com/android/server/wm/DeviceStateController.java
+++ b/services/core/java/com/android/server/wm/DeviceStateController.java
@@ -16,80 +16,92 @@
 
 package com.android.server.wm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 
+import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 
 /**
- * Class that registers callbacks with the {@link DeviceStateManager} and
- * responds to fold state changes by forwarding such events to a delegate.
+ * Class that registers callbacks with the {@link DeviceStateManager} and responds to device
+ * changes.
  */
-final class DeviceStateController {
+final class DeviceStateController implements DeviceStateManager.DeviceStateCallback {
+
+    @NonNull
     private final DeviceStateManager mDeviceStateManager;
-    private final Context mContext;
+    @NonNull
+    private final int[] mOpenDeviceStates;
+    @NonNull
+    private final int[] mHalfFoldedDeviceStates;
+    @NonNull
+    private final int[] mFoldedDeviceStates;
+    @NonNull
+    private final int[] mRearDisplayDeviceStates;
+    @NonNull
+    private final List<Consumer<DeviceState>> mDeviceStateCallbacks = new ArrayList<>();
 
-    private FoldStateListener mDeviceStateListener;
+    @Nullable
+    private DeviceState mLastDeviceState;
 
-    public enum FoldState {
-        UNKNOWN, OPEN, FOLDED, HALF_FOLDED
+    public enum DeviceState {
+        UNKNOWN, OPEN, FOLDED, HALF_FOLDED, REAR,
     }
 
-    DeviceStateController(Context context, Handler handler, Consumer<FoldState> delegate) {
-        mContext = context;
-        mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+    DeviceStateController(@NonNull Context context, @NonNull Handler handler) {
+        mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
+        mOpenDeviceStates = context.getResources()
+                .getIntArray(R.array.config_openDeviceStates);
+        mHalfFoldedDeviceStates = context.getResources()
+                .getIntArray(R.array.config_halfFoldedDeviceStates);
+        mFoldedDeviceStates = context.getResources()
+                .getIntArray(R.array.config_foldedDeviceStates);
+        mRearDisplayDeviceStates = context.getResources()
+                .getIntArray(R.array.config_rearDisplayDeviceStates);
+
         if (mDeviceStateManager != null) {
-            mDeviceStateListener = new FoldStateListener(mContext, delegate);
-            mDeviceStateManager
-                    .registerCallback(new HandlerExecutor(handler),
-                            mDeviceStateListener);
+            mDeviceStateManager.registerCallback(new HandlerExecutor(handler), this);
         }
     }
 
     void unregisterFromDeviceStateManager() {
-        if (mDeviceStateListener != null) {
-            mDeviceStateManager.unregisterCallback(mDeviceStateListener);
+        if (mDeviceStateManager != null) {
+            mDeviceStateManager.unregisterCallback(this);
         }
     }
 
-    /**
-     * A listener for half-fold device state events that dispatches state changes to a delegate.
-     */
-    static final class FoldStateListener implements DeviceStateManager.DeviceStateCallback {
+    void registerDeviceStateCallback(@NonNull Consumer<DeviceState> callback) {
+        mDeviceStateCallbacks.add(callback);
+    }
 
-        private final int[] mHalfFoldedDeviceStates;
-        private final int[] mFoldedDeviceStates;
-
-        @Nullable
-        private FoldState mLastResult;
-        private final Consumer<FoldState> mDelegate;
-
-        FoldStateListener(Context context, Consumer<FoldState> delegate) {
-            mFoldedDeviceStates = context.getResources().getIntArray(
-                    com.android.internal.R.array.config_foldedDeviceStates);
-            mHalfFoldedDeviceStates = context.getResources().getIntArray(
-                    com.android.internal.R.array.config_halfFoldedDeviceStates);
-            mDelegate = delegate;
+    @Override
+    public void onStateChanged(int state) {
+        final DeviceState deviceState;
+        if (ArrayUtils.contains(mHalfFoldedDeviceStates, state)) {
+            deviceState = DeviceState.HALF_FOLDED;
+        } else if (ArrayUtils.contains(mFoldedDeviceStates, state)) {
+            deviceState = DeviceState.FOLDED;
+        } else if (ArrayUtils.contains(mRearDisplayDeviceStates, state)) {
+            deviceState = DeviceState.REAR;
+        } else if (ArrayUtils.contains(mOpenDeviceStates, state)) {
+            deviceState = DeviceState.OPEN;
+        } else {
+            deviceState = DeviceState.UNKNOWN;
         }
 
-        @Override
-        public void onStateChanged(int state) {
-            final boolean halfFolded = ArrayUtils.contains(mHalfFoldedDeviceStates, state);
-            FoldState result;
-            if (halfFolded) {
-                result = FoldState.HALF_FOLDED;
-            } else {
-                final boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state);
-                result = folded ? FoldState.FOLDED : FoldState.OPEN;
-            }
-            if (mLastResult == null || !mLastResult.equals(result)) {
-                mLastResult = result;
-                mDelegate.accept(result);
+        if (mLastDeviceState == null || !mLastDeviceState.equals(deviceState)) {
+            mLastDeviceState = deviceState;
+
+            for (Consumer<DeviceState> callback : mDeviceStateCallbacks) {
+                callback.accept(mLastDeviceState);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9af1b2b..740fd584 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1125,14 +1125,17 @@
                     mWmService.mAtmService.getRecentTasks().getInputListener());
         }
 
+        mDeviceStateController = new DeviceStateController(mWmService.mContext, mWmService.mH);
+
         mDisplayPolicy = new DisplayPolicy(mWmService, this);
         mDisplayRotation = new DisplayRotation(mWmService, this, mDisplayInfo.address);
 
-        mDeviceStateController = new DeviceStateController(mWmService.mContext, mWmService.mH,
-                newFoldState -> {
+        final Consumer<DeviceStateController.DeviceState> deviceStateConsumer =
+                (@NonNull DeviceStateController.DeviceState newFoldState) -> {
                     mDisplaySwitchTransitionLauncher.foldStateChanged(newFoldState);
                     mDisplayRotation.foldStateChanged(newFoldState);
-                });
+                };
+        mDeviceStateController.registerDeviceStateCallback(deviceStateConsumer);
 
         mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
                 R.dimen.config_closeToSquareDisplayMaxAspectRatio);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index e6d8b3d..a1e18cf 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -1573,7 +1573,7 @@
         proto.end(token);
     }
 
-    boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
+    boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
         if (mFoldController == null) return false;
         return mFoldController.isDeviceInPosture(state, isTabletop);
     }
@@ -1585,10 +1585,10 @@
     /**
      * Called by the DeviceStateManager callback when the device state changes.
      */
-    void foldStateChanged(DeviceStateController.FoldState foldState) {
+    void foldStateChanged(DeviceStateController.DeviceState deviceState) {
         if (mFoldController != null) {
             synchronized (mLock) {
-                mFoldController.foldStateChanged(foldState);
+                mFoldController.foldStateChanged(deviceState);
             }
         }
     }
@@ -1596,8 +1596,8 @@
     private class FoldController {
         @Surface.Rotation
         private int mHalfFoldSavedRotation = -1; // No saved rotation
-        private DeviceStateController.FoldState mFoldState =
-                DeviceStateController.FoldState.UNKNOWN;
+        private DeviceStateController.DeviceState mDeviceState =
+                DeviceStateController.DeviceState.UNKNOWN;
         private boolean mInHalfFoldTransition = false;
         private final boolean mIsDisplayAlwaysSeparatingHinge;
         private final Set<Integer> mTabletopRotations;
@@ -1637,32 +1637,33 @@
                     R.bool.config_isDisplayHingeAlwaysSeparating);
         }
 
-        boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
-            if (state != mFoldState) {
+        boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
+            if (state != mDeviceState) {
                 return false;
             }
-            if (mFoldState == DeviceStateController.FoldState.HALF_FOLDED) {
+            if (mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) {
                 return !(isTabletop ^ mTabletopRotations.contains(mRotation));
             }
             return true;
         }
 
-        DeviceStateController.FoldState getFoldState() {
-            return mFoldState;
+        DeviceStateController.DeviceState getFoldState() {
+            return mDeviceState;
         }
 
         boolean isSeparatingHinge() {
-            return mFoldState == DeviceStateController.FoldState.HALF_FOLDED
-                    || (mFoldState == DeviceStateController.FoldState.OPEN
+            return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED
+                    || (mDeviceState == DeviceStateController.DeviceState.OPEN
                         && mIsDisplayAlwaysSeparatingHinge);
         }
 
         boolean overrideFrozenRotation() {
-            return mFoldState == DeviceStateController.FoldState.HALF_FOLDED;
+            return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED;
         }
 
         boolean shouldRevertOverriddenRotation() {
-            return mFoldState == DeviceStateController.FoldState.OPEN // When transitioning to open.
+            // When transitioning to open.
+            return mDeviceState == DeviceStateController.DeviceState.OPEN
                     && mInHalfFoldTransition
                     && mHalfFoldSavedRotation != -1 // Ignore if we've already reverted.
                     && mUserRotationMode
@@ -1676,30 +1677,30 @@
             return savedRotation;
         }
 
-        void foldStateChanged(DeviceStateController.FoldState newState) {
+        void foldStateChanged(DeviceStateController.DeviceState newState) {
             ProtoLog.v(WM_DEBUG_ORIENTATION,
                     "foldStateChanged: displayId %d, halfFoldStateChanged %s, "
                     + "saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, "
                     + "mLastOrientation: %d, mRotation: %d",
                     mDisplayContent.getDisplayId(), newState.name(), mHalfFoldSavedRotation,
                     mUserRotation, mLastSensorRotation, mLastOrientation, mRotation);
-            if (mFoldState == DeviceStateController.FoldState.UNKNOWN) {
-                mFoldState = newState;
+            if (mDeviceState == DeviceStateController.DeviceState.UNKNOWN) {
+                mDeviceState = newState;
                 return;
             }
-            if (newState == DeviceStateController.FoldState.HALF_FOLDED
-                    && mFoldState != DeviceStateController.FoldState.HALF_FOLDED) {
+            if (newState == DeviceStateController.DeviceState.HALF_FOLDED
+                    && mDeviceState != DeviceStateController.DeviceState.HALF_FOLDED) {
                 // The device has transitioned to HALF_FOLDED state: save the current rotation and
                 // update the device rotation.
                 mHalfFoldSavedRotation = mRotation;
-                mFoldState = newState;
+                mDeviceState = newState;
                 // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will
                 // return true, so rotation is unlocked.
                 mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
             } else {
                 mInHalfFoldTransition = true;
-                mFoldState = newState;
+                mDeviceState = newState;
                 // Tell the device to update its orientation.
                 mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
@@ -1822,7 +1823,7 @@
             final long mTimestamp = System.currentTimeMillis();
             final int mHalfFoldSavedRotation;
             final boolean mInHalfFoldTransition;
-            final DeviceStateController.FoldState mFoldState;
+            final DeviceStateController.DeviceState mDeviceState;
             @Nullable final String mDisplayRotationCompatPolicySummary;
 
             Record(DisplayRotation dr, int fromRotation, int toRotation) {
@@ -1852,11 +1853,11 @@
                 if (dr.mFoldController != null) {
                     mHalfFoldSavedRotation = dr.mFoldController.mHalfFoldSavedRotation;
                     mInHalfFoldTransition = dr.mFoldController.mInHalfFoldTransition;
-                    mFoldState = dr.mFoldController.mFoldState;
+                    mDeviceState = dr.mFoldController.mDeviceState;
                 } else {
                     mHalfFoldSavedRotation = NO_FOLD_CONTROLLER;
                     mInHalfFoldTransition = false;
-                    mFoldState = DeviceStateController.FoldState.UNKNOWN;
+                    mDeviceState = DeviceStateController.DeviceState.UNKNOWN;
                 }
                 mDisplayRotationCompatPolicySummary = dc.mDisplayRotationCompatPolicy == null
                         ? null
@@ -1882,7 +1883,7 @@
                     pw.println(prefix + " halfFoldSavedRotation="
                             + mHalfFoldSavedRotation
                             + " mInHalfFoldTransition=" + mInHalfFoldTransition
-                            + " mFoldState=" + mFoldState);
+                            + " mFoldState=" + mDeviceState);
                 }
                 if (mDisplayRotationCompatPolicySummary != null) {
                     pw.println(prefix + mDisplayRotationCompatPolicySummary);
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 73d1ff9d..b67b745 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -542,7 +542,7 @@
     // Note that we check the task rather than the parent as with ActivityEmbedding the parent might
     // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is
     // actually fullscreen.
-    private boolean isDisplayFullScreenAndInPosture(DeviceStateController.FoldState state,
+    private boolean isDisplayFullScreenAndInPosture(DeviceStateController.DeviceState state,
             boolean isTabletop) {
         Task task = mActivityRecord.getTask();
         return mActivityRecord.mDisplayContent != null
@@ -568,7 +568,7 @@
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
         boolean bookMode = isDisplayFullScreenAndInPosture(
-                DeviceStateController.FoldState.HALF_FOLDED, false /* isTabletop */);
+                DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */);
         return isHorizontalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
@@ -580,7 +580,7 @@
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
         boolean tabletopMode = isDisplayFullScreenAndInPosture(
-                DeviceStateController.FoldState.HALF_FOLDED, true /* isTabletop */);
+                DeviceStateController.DeviceState.HALF_FOLDED, true /* isTabletop */);
         return isVerticalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
@@ -1107,7 +1107,7 @@
             int letterboxPositionForHorizontalReachability = getLetterboxConfiguration()
                     .getLetterboxPositionForHorizontalReachability(
                             isDisplayFullScreenAndInPosture(
-                                    DeviceStateController.FoldState.HALF_FOLDED,
+                                    DeviceStateController.DeviceState.HALF_FOLDED,
                                     false /* isTabletop */));
             positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPosition(
                     letterboxPositionForHorizontalReachability);
@@ -1115,7 +1115,7 @@
             int letterboxPositionForVerticalReachability = getLetterboxConfiguration()
                     .getLetterboxPositionForVerticalReachability(
                             isDisplayFullScreenAndInPosture(
-                                    DeviceStateController.FoldState.HALF_FOLDED,
+                                    DeviceStateController.DeviceState.HALF_FOLDED,
                                     true /* isTabletop */));
             positionToLog = letterboxVerticalReachabilityPositionToLetterboxPosition(
                     letterboxPositionForVerticalReachability);
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 30bdc34..2edb082 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -51,10 +51,10 @@
     /**
      *   Called by the DeviceStateManager callback when the state changes.
      */
-    void foldStateChanged(DeviceStateController.FoldState newFoldState) {
+    void foldStateChanged(DeviceStateController.DeviceState newDeviceState) {
         // Ignore transitions to/from half-folded.
-        if (newFoldState == DeviceStateController.FoldState.HALF_FOLDED) return;
-        mIsFolded = newFoldState == DeviceStateController.FoldState.FOLDED;
+        if (newDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) return;
+        mIsFolded = newDeviceState == DeviceStateController.DeviceState.FOLDED;
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
index 86732c9..2a28ae2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
@@ -16,13 +16,12 @@
 
 package com.android.server.wm;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -32,9 +31,10 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 
 import java.util.function.Consumer;
 
@@ -48,92 +48,76 @@
 @Presubmit
 public class DeviceStateControllerTests {
 
-    private DeviceStateController.FoldStateListener mFoldStateListener;
     private DeviceStateController mTarget;
     private DeviceStateControllerBuilder mBuilder;
 
     private Context mMockContext;
-    private Handler mMockHandler;
-    private Resources mMockRes;
     private DeviceStateManager mMockDeviceStateManager;
-
-    private Consumer<DeviceStateController.FoldState> mDelegate;
-    private DeviceStateController.FoldState mCurrentState = DeviceStateController.FoldState.UNKNOWN;
+    private DeviceStateController.DeviceState mCurrentState =
+            DeviceStateController.DeviceState.UNKNOWN;
 
     @Before
     public void setUp() {
         mBuilder = new DeviceStateControllerBuilder();
-        mCurrentState = DeviceStateController.FoldState.UNKNOWN;
+        mCurrentState = DeviceStateController.DeviceState.UNKNOWN;
     }
 
-    private void initialize(boolean supportFold, boolean supportHalfFold) throws Exception {
+    private void initialize(boolean supportFold, boolean supportHalfFold) {
         mBuilder.setSupportFold(supportFold, supportHalfFold);
-        mDelegate = (newFoldState) -> {
+        Consumer<DeviceStateController.DeviceState> delegate = (newFoldState) -> {
             mCurrentState = newFoldState;
         };
-        mBuilder.setDelegate(mDelegate);
+        mBuilder.setDelegate(delegate);
         mBuilder.build();
-        verifyFoldStateListenerRegistration(1);
+        verify(mMockDeviceStateManager).registerCallback(any(), any());
     }
 
     @Test
-    public void testInitialization() throws Exception {
+    public void testInitialization() {
         initialize(true /* supportFold */, true /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
+        mTarget.onStateChanged(mOpenDeviceStates[0]);
+        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
     }
 
     @Test
-    public void testInitializationWithNoFoldSupport() throws Exception {
+    public void testInitializationWithNoFoldSupport() {
         initialize(false /* supportFold */, false /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mFoldedStates[0]);
+        mTarget.onStateChanged(mFoldedStates[0]);
         // Note that the folded state is ignored.
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
+        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState);
     }
 
     @Test
-    public void testWithFoldSupported() throws Exception {
+    public void testWithFoldSupported() {
         initialize(true /* supportFold */, false /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
-        mFoldStateListener.onStateChanged(mFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.FOLDED);
-        mFoldStateListener.onStateChanged(mHalfFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN); // Ignored
+        mTarget.onStateChanged(mOpenDeviceStates[0]);
+        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+        mTarget.onStateChanged(mFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+        mTarget.onStateChanged(mHalfFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
     }
 
     @Test
-    public void testWithHalfFoldSupported() throws Exception {
+    public void testWithHalfFoldSupported() {
         initialize(true /* supportFold */, true /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
-        mFoldStateListener.onStateChanged(mFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.FOLDED);
-        mFoldStateListener.onStateChanged(mHalfFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.HALF_FOLDED);
+        mTarget.onStateChanged(mOpenDeviceStates[0]);
+        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+        mTarget.onStateChanged(mFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+        mTarget.onStateChanged(mHalfFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
     }
 
-
     private final int[] mFoldedStates = {0};
-    private final int[] mUnfoldedStates = {1};
+    private final int[] mOpenDeviceStates = {1};
     private final int[] mHalfFoldedStates = {2};
-
-
-    private void verifyFoldStateListenerRegistration(int numOfInvocation) {
-        final ArgumentCaptor<DeviceStateController.FoldStateListener> listenerCaptor =
-                ArgumentCaptor.forClass(DeviceStateController.FoldStateListener.class);
-        verify(mMockDeviceStateManager, times(numOfInvocation)).registerCallback(
-                any(),
-                listenerCaptor.capture());
-        if (numOfInvocation > 0) {
-            mFoldStateListener = listenerCaptor.getValue();
-        }
-    }
+    private final int[] mRearDisplayStates = {3};
 
     private class DeviceStateControllerBuilder {
         private boolean mSupportFold = false;
         private boolean mSupportHalfFold = false;
-        private Consumer<DeviceStateController.FoldState> mDelegate;
+        private Consumer<DeviceStateController.DeviceState> mDelegate;
 
         DeviceStateControllerBuilder setSupportFold(
                 boolean supportFold, boolean supportHalfFold) {
@@ -143,34 +127,44 @@
         }
 
         DeviceStateControllerBuilder setDelegate(
-                Consumer<DeviceStateController.FoldState> delegate) {
+                Consumer<DeviceStateController.DeviceState> delegate) {
             mDelegate = delegate;
             return this;
         }
 
         private void mockFold(boolean enableFold, boolean enableHalfFold) {
+            if (enableFold || enableHalfFold) {
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_openDeviceStates))
+                        .thenReturn(mOpenDeviceStates);
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_rearDisplayDeviceStates))
+                        .thenReturn(mRearDisplayStates);
+            }
+
             if (enableFold) {
-                when(mMockContext.getResources().getIntArray(
-                        com.android.internal.R.array.config_foldedDeviceStates))
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_foldedDeviceStates))
                         .thenReturn(mFoldedStates);
             }
             if (enableHalfFold) {
-                when(mMockContext.getResources().getIntArray(
-                        com.android.internal.R.array.config_halfFoldedDeviceStates))
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_halfFoldedDeviceStates))
                         .thenReturn(mHalfFoldedStates);
             }
         }
 
-        private void build() throws Exception {
+        private void build() {
             mMockContext = mock(Context.class);
-            mMockRes = mock(Resources.class);
-            when(mMockContext.getResources()).thenReturn((mMockRes));
             mMockDeviceStateManager = mock(DeviceStateManager.class);
             when(mMockContext.getSystemService(DeviceStateManager.class))
                     .thenReturn(mMockDeviceStateManager);
+            Resources mockRes = mock(Resources.class);
+            when(mMockContext.getResources()).thenReturn((mockRes));
             mockFold(mSupportFold, mSupportHalfFold);
-            mMockHandler = mock(Handler.class);
-            mTarget = new DeviceStateController(mMockContext, mMockHandler, mDelegate);
+            Handler mockHandler = mock(Handler.class);
+            mTarget = new DeviceStateController(mMockContext, mockHandler);
+            mTarget.registerDeviceStateCallback(mDelegate);
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 4ce43e1..f814608 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -705,7 +705,7 @@
 
         enableOrientationSensor();
 
-        mTarget.foldStateChanged(DeviceStateController.FoldState.OPEN);
+        mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
         freezeRotation(Surface.ROTATION_270);
 
         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
@@ -715,7 +715,7 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
         // ... until half-fold
-        mTarget.foldStateChanged(DeviceStateController.FoldState.HALF_FOLDED);
+        mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
         verify(sMockWm).updateRotation(false, false);
         assertTrue(waitForUiHandler());
@@ -723,7 +723,7 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
         // ... then transition back to flat
-        mTarget.foldStateChanged(DeviceStateController.FoldState.OPEN);
+        mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
         assertTrue(waitForUiHandler());
         verify(sMockWm, atLeast(1)).updateRotation(false, false);
         assertTrue(waitForUiHandler());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 46d69d1..a09bb33 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -98,7 +98,7 @@
 import com.android.internal.policy.SystemBarUtils;
 import com.android.internal.statusbar.LetterboxDetails;
 import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.wm.DeviceStateController.FoldState;
+import com.android.server.wm.DeviceStateController.DeviceState;
 
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -3186,9 +3186,9 @@
     private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) {
         final DisplayRotation r = mActivity.mDisplayContent.getDisplayRotation();
         doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge();
-        doReturn(false).when(r).isDeviceInPosture(any(FoldState.class), anyBoolean());
+        doReturn(false).when(r).isDeviceInPosture(any(DeviceState.class), anyBoolean());
         if (isHalfFolded) {
-            doReturn(true).when(r).isDeviceInPosture(FoldState.HALF_FOLDED, isTabletop);
+            doReturn(true).when(r).isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop);
         }
         mActivity.recomputeConfiguration();
     }
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 42a5af7..17c354a 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -36,6 +36,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -106,6 +107,12 @@
         return false;
     }
 
+    /**
+     * List of connected MIDI devices
+     */
+    private final HashMap<String, UsbMidiDevice>
+            mMidiDevices = new HashMap<String, UsbMidiDevice>();
+
     // UsbMidiDevice for USB peripheral mode (gadget) device
     private UsbMidiDevice mPeripheralMidiDevice = null;
 
@@ -249,6 +256,8 @@
             }
         }
 
+        addMidiDevice(deviceAddress, usbDevice, parser, cardRec);
+
         logDevices("deviceAdded()");
 
         if (DEBUG) {
@@ -256,6 +265,54 @@
         }
     }
 
+    private void addMidiDevice(String deviceAddress, UsbDevice usbDevice,
+            UsbDescriptorParser parser, AlsaCardsParser.AlsaCardRecord cardRec) {
+        boolean hasMidi = parser.hasMIDIInterface();
+        // UsbHostManager will create UsbDirectMidiDevices instead if MIDI 2 is supported.
+        boolean hasMidi2 = parser.containsUniversalMidiDeviceEndpoint();
+        if (DEBUG) {
+            Slog.d(TAG, "hasMidi: " + hasMidi + " mHasMidiFeature:" + mHasMidiFeature);
+            Slog.d(TAG, "hasMidi2: " + hasMidi2);
+        }
+        if (mHasMidiFeature && hasMidi && !hasMidi2) {
+            Bundle properties = new Bundle();
+            String manufacturer = usbDevice.getManufacturerName();
+            String product = usbDevice.getProductName();
+            String version = usbDevice.getVersion();
+            String name;
+            if (manufacturer == null || manufacturer.isEmpty()) {
+                name = product;
+            } else if (product == null || product.isEmpty()) {
+                name = manufacturer;
+            } else {
+                name = manufacturer + " " + product;
+            }
+            properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
+            properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
+            properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+            properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
+            properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+                    usbDevice.getSerialNumber());
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, cardRec.getCardNum());
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, 0 /*deviceNum*/);
+            properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
+
+            int numLegacyMidiInputs = parser.calculateNumLegacyMidiInputs();
+            int numLegacyMidiOutputs = parser.calculateNumLegacyMidiOutputs();
+            if (DEBUG) {
+                Slog.d(TAG, "numLegacyMidiInputs: " + numLegacyMidiInputs);
+                Slog.d(TAG, "numLegacyMidiOutputs:" + numLegacyMidiOutputs);
+            }
+
+            UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
+                    cardRec.getCardNum(), 0 /*device*/, numLegacyMidiInputs,
+                    numLegacyMidiOutputs);
+            if (usbMidiDevice != null) {
+                mMidiDevices.put(deviceAddress, usbMidiDevice);
+            }
+        }
+    }
+
     /* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
         if (DEBUG) {
             Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
@@ -269,6 +326,13 @@
             selectDefaultDevice(); // if there any external devices left, select one of them
         }
 
+        // MIDI
+        UsbMidiDevice usbMidiDevice = mMidiDevices.remove(deviceAddress);
+        if (usbMidiDevice != null) {
+            Slog.i(TAG, "USB MIDI Device Removed: " + deviceAddress);
+            IoUtils.closeQuietly(usbMidiDevice);
+        }
+
         logDevices("usbDeviceRemoved()");
 
     }
@@ -324,6 +388,12 @@
             usbAlsaDevice.dump(dump, "alsa_devices", UsbAlsaManagerProto.ALSA_DEVICES);
         }
 
+        for (String deviceAddr : mMidiDevices.keySet()) {
+            // A UsbMidiDevice does not have a handle to the UsbDevice anymore
+            mMidiDevices.get(deviceAddr).dump(deviceAddr, dump, "midi_devices",
+                    UsbAlsaManagerProto.MIDI_DEVICES);
+        }
+
         dump.end(token);
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index f389276..b3eb285 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -444,14 +444,19 @@
                         } else {
                             Slog.e(TAG, "Universal Midi Device is null.");
                         }
-                    }
-                    if (parser.containsLegacyMidiDeviceEndpoint()) {
-                        UsbDirectMidiDevice midiDevice = UsbDirectMidiDevice.create(mContext,
-                                newDevice, parser, false, uniqueUsbDeviceIdentifier);
-                        if (midiDevice != null) {
-                            midiDevices.add(midiDevice);
-                        } else {
-                            Slog.e(TAG, "Legacy Midi Device is null.");
+
+                        // Use UsbDirectMidiDevice only if this supports MIDI 2.0 as well.
+                        // ALSA removes the audio sound card if MIDI interfaces are removed.
+                        // This means that as long as ALSA is used for audio, MIDI 1.0 USB
+                        // devices should use the ALSA path for MIDI.
+                        if (parser.containsLegacyMidiDeviceEndpoint()) {
+                            midiDevice = UsbDirectMidiDevice.create(mContext,
+                                    newDevice, parser, false, uniqueUsbDeviceIdentifier);
+                            if (midiDevice != null) {
+                                midiDevices.add(midiDevice);
+                            } else {
+                                Slog.e(TAG, "Legacy Midi Device is null.");
+                            }
                         }
                     }
 
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 3f2d8c8..c6ea228 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -79,6 +79,10 @@
         mInterfaceDescriptors.add(interfaceDesc);
     }
 
+    ArrayList<UsbInterfaceDescriptor> getInterfaceDescriptors() {
+        return mInterfaceDescriptors;
+    }
+
     private boolean isAudioInterface(UsbInterfaceDescriptor descriptor) {
         return descriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO
                 && descriptor.getUsbSubclass() == UsbDescriptor.AUDIO_AUDIOSTREAMING;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index cd6ea68..626ce89 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -40,6 +40,7 @@
     private UsbDeviceDescriptor mDeviceDescriptor;
     private UsbConfigDescriptor mCurConfigDescriptor;
     private UsbInterfaceDescriptor mCurInterfaceDescriptor;
+    private UsbEndpointDescriptor mCurEndpointDescriptor;
 
     // The AudioClass spec implemented by the AudioClass Interfaces
     // This may well be different than the overall USB Spec.
@@ -165,7 +166,7 @@
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
-                descriptor = new UsbEndpointDescriptor(length, type);
+                descriptor = mCurEndpointDescriptor = new UsbEndpointDescriptor(length, type);
                 if (mCurInterfaceDescriptor != null) {
                     mCurInterfaceDescriptor.addEndpointDescriptor(
                             (UsbEndpointDescriptor) descriptor);
@@ -265,6 +266,9 @@
                                     + Integer.toHexString(subClass));
                             break;
                     }
+                    if (mCurEndpointDescriptor != null && descriptor != null) {
+                        mCurEndpointDescriptor.setClassSpecificEndpointDescriptor(descriptor);
+                    }
                 }
                 break;
 
@@ -798,6 +802,84 @@
     /**
      * @hide
      */
+    private int calculateNumLegacyMidiPorts(boolean isOutput) {
+        // Only look at the first config.
+        UsbConfigDescriptor configDescriptor = null;
+        for (UsbDescriptor descriptor : mDescriptors) {
+            if (descriptor.getType() == UsbDescriptor.DESCRIPTORTYPE_CONFIG) {
+                if (descriptor instanceof UsbConfigDescriptor) {
+                    configDescriptor = (UsbConfigDescriptor) descriptor;
+                    break;
+                } else {
+                    Log.w(TAG, "Unrecognized Config l: " + descriptor.getLength()
+                            + " t:0x" + Integer.toHexString(descriptor.getType()));
+                }
+            }
+        }
+        if (configDescriptor == null) {
+            Log.w(TAG, "Config not found");
+            return 0;
+        }
+
+        ArrayList<UsbInterfaceDescriptor> legacyMidiInterfaceDescriptors =
+                new ArrayList<UsbInterfaceDescriptor>();
+        for (UsbInterfaceDescriptor interfaceDescriptor
+                : configDescriptor.getInterfaceDescriptors()) {
+            if (interfaceDescriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO) {
+                if (interfaceDescriptor.getUsbSubclass() == UsbDescriptor.AUDIO_MIDISTREAMING) {
+                    UsbDescriptor midiHeaderDescriptor =
+                            interfaceDescriptor.getMidiHeaderInterfaceDescriptor();
+                    if (midiHeaderDescriptor != null) {
+                        if (midiHeaderDescriptor instanceof UsbMSMidiHeader) {
+                            UsbMSMidiHeader midiHeader =
+                                    (UsbMSMidiHeader) midiHeaderDescriptor;
+                            if (midiHeader.getMidiStreamingClass() == MS_MIDI_1_0) {
+                                legacyMidiInterfaceDescriptors.add(interfaceDescriptor);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        int count = 0;
+        for (UsbInterfaceDescriptor interfaceDescriptor : legacyMidiInterfaceDescriptors) {
+            for (int i = 0; i < interfaceDescriptor.getNumEndpoints(); i++) {
+                UsbEndpointDescriptor endpoint =
+                        interfaceDescriptor.getEndpointDescriptor(i);
+                // 0 is output, 1 << 7 is input.
+                if ((endpoint.getDirection() == 0) == isOutput) {
+                    UsbDescriptor classSpecificEndpointDescriptor =
+                            endpoint.getClassSpecificEndpointDescriptor();
+                    if (classSpecificEndpointDescriptor != null
+                            && (classSpecificEndpointDescriptor instanceof UsbACMidi10Endpoint)) {
+                        UsbACMidi10Endpoint midiEndpoint =
+                                (UsbACMidi10Endpoint) classSpecificEndpointDescriptor;
+                        count += midiEndpoint.getNumJacks();
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    /**
+     * @hide
+     */
+    public int calculateNumLegacyMidiInputs() {
+        return calculateNumLegacyMidiPorts(false /*isOutput*/);
+    }
+
+    /**
+     * @hide
+     */
+    public int calculateNumLegacyMidiOutputs() {
+        return calculateNumLegacyMidiPorts(true /*isOutput*/);
+    }
+
+    /**
+     * @hide
+     */
     public float getInputHeadsetProbability() {
         if (hasMIDIInterface()) {
             return 0.0f;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index ab07ce7..1f448ac 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -79,6 +79,8 @@
     private byte mRefresh;
     private byte mSyncAddress;
 
+    private UsbDescriptor mClassSpecificEndpointDescriptor;
+
     public UsbEndpointDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 4;
@@ -112,6 +114,14 @@
         return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION;
     }
 
+    void setClassSpecificEndpointDescriptor(UsbDescriptor descriptor) {
+        mClassSpecificEndpointDescriptor = descriptor;
+    }
+
+    UsbDescriptor getClassSpecificEndpointDescriptor() {
+        return mClassSpecificEndpointDescriptor;
+    }
+
     /**
     * Returns a UsbEndpoint that this UsbEndpointDescriptor is describing.
     */