Hide views on lockscreen when wallpaper dream is active

When dreaming, only keyguard clock is visible on lockscreen.

Bug: b/285061111
Test: atest LockIconViewControllerWithCoroutinesTest
Test: atest KeyguardClockSwitchControllerWithCoroutinesTest
Test: atest KeyguardIndicationControllerWithCoroutinesTest
Change-Id: Ic38ad5c8260bb4869508a2d7b27ecd39a72d341e
Merged-In: Ic38ad5c8260bb4869508a2d7b27ecd39a72d341e
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 6c98376..16eb21d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -21,6 +21,8 @@
 
 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.annotation.Nullable;
 import android.database.ContentObserver;
@@ -33,12 +35,15 @@
 import android.widget.LinearLayout;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.LogLevel;
 import com.android.systemui.log.dagger.KeyguardClockLog;
@@ -58,6 +63,7 @@
 
 import java.io.PrintWriter;
 import java.util.Locale;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -99,8 +105,20 @@
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
 
     private boolean mOnlyClock = false;
+    private boolean mIsActiveDreamLockscreenHosted = false;
+    private FeatureFlags mFeatureFlags;
+    private KeyguardInteractor mKeyguardInteractor;
     private final DelayableExecutor mUiExecutor;
     private boolean mCanShowDoubleLineClock = true;
+    @VisibleForTesting
+    final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
+            (Boolean isLockscreenHosted) -> {
+                if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) {
+                    return;
+                }
+                mIsActiveDreamLockscreenHosted = isLockscreenHosted;
+                updateKeyguardStatusAreaVisibility();
+            };
     private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
         @Override
         public void onChange(boolean change) {
@@ -137,7 +155,9 @@
             @Main DelayableExecutor uiExecutor,
             DumpManager dumpManager,
             ClockEventController clockEventController,
-            @KeyguardClockLog LogBuffer logBuffer) {
+            @KeyguardClockLog LogBuffer logBuffer,
+            KeyguardInteractor keyguardInteractor,
+            FeatureFlags featureFlags) {
         super(keyguardClockSwitch);
         mStatusBarStateController = statusBarStateController;
         mClockRegistry = clockRegistry;
@@ -151,6 +171,8 @@
         mClockEventController = clockEventController;
         mLogBuffer = logBuffer;
         mView.setLogBuffer(mLogBuffer);
+        mFeatureFlags = featureFlags;
+        mKeyguardInteractor = keyguardInteractor;
 
         mClockChangedListener = new ClockRegistry.ClockChangeListener() {
             @Override
@@ -191,6 +213,12 @@
 
         mDumpManager.unregisterDumpable(getClass().toString()); // unregister previous clocks
         mDumpManager.registerDumpable(getClass().toString(), this);
+
+        if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
+            mStatusArea = mView.findViewById(R.id.keyguard_status_area);
+            collectFlow(mStatusArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
+                    mIsActiveDreamLockscreenHostedCallback);
+        }
     }
 
     @Override
@@ -524,6 +552,15 @@
         }
     }
 
+    private void updateKeyguardStatusAreaVisibility() {
+        if (mStatusArea != null) {
+            mUiExecutor.execute(() -> {
+                mStatusArea.setVisibility(
+                        mIsActiveDreamLockscreenHosted ? View.INVISIBLE : View.VISIBLE);
+            });
+        }
+    }
+
     /**
      * Sets the clipChildren property on relevant views, to allow the smartspace to draw out of
      * bounds during the unlock transition.
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8ef6c2e..5459718 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -24,6 +24,7 @@
 import static com.android.keyguard.LockIconView.ICON_UNLOCK;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.content.res.Configuration;
@@ -124,6 +125,7 @@
     private int mActivePointerId = -1;
 
     private boolean mIsDozing;
+    private boolean mIsActiveDreamLockscreenHosted;
     private boolean mIsBouncerShowing;
     private boolean mRunningFPS;
     private boolean mCanDismissLockScreen;
@@ -165,6 +167,13 @@
         updateVisibility();
     };
 
+    @VisibleForTesting
+    final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
+            (Boolean isLockscreenHosted) -> {
+                mIsActiveDreamLockscreenHosted = isLockscreenHosted;
+                updateVisibility();
+            };
+
     @Inject
     public LockIconViewController(
             @Nullable LockIconView view,
@@ -224,6 +233,11 @@
                     mDozeTransitionCallback);
             collectFlow(mView, mKeyguardInteractor.isDozing(), mIsDozingCallback);
         }
+
+        if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
+            collectFlow(mView, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
+                    mIsActiveDreamLockscreenHostedCallback);
+        }
     }
 
     @Override
@@ -289,6 +303,11 @@
             return;
         }
 
+        if (mIsKeyguardShowing && mIsActiveDreamLockscreenHosted) {
+            mView.setVisibility(View.INVISIBLE);
+            return;
+        }
+
         boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon
                 && !mShowAodUnlockedIcon && !mShowAodLockIcon;
         mShowLockIcon = !mCanDismissLockScreen && isLockScreen()
@@ -436,6 +455,7 @@
         pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
         pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
         pw.println(" mDefaultPaddingPx: " + mDefaultPaddingPx);
+        pw.println(" mIsActiveDreamLockscreenHosted: " + mIsActiveDreamLockscreenHosted);
 
         if (mView != null) {
             mView.dump(pw, args);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 42ebaa3..73d8445 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -29,6 +29,7 @@
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
@@ -43,6 +44,7 @@
 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
 import static com.android.systemui.log.core.LogLevel.ERROR;
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.app.AlarmManager;
 import android.app.admin.DevicePolicyManager;
@@ -96,6 +98,7 @@
 import com.android.systemui.keyguard.KeyguardIndication;
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
 import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.keyguard.util.IndicationHelper;
 import com.android.systemui.log.core.LogLevel;
 import com.android.systemui.plugins.FalsingManager;
@@ -114,6 +117,7 @@
 import java.text.NumberFormat;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -171,7 +175,7 @@
     public KeyguardIndicationRotateTextViewController mRotateTextViewController;
     private BroadcastReceiver mBroadcastReceiver;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-
+    private KeyguardInteractor mKeyguardInteractor;
     private String mPersistentUnlockMessage;
     private String mAlignmentIndication;
     private CharSequence mTrustGrantedIndication;
@@ -205,7 +209,17 @@
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
 
     private boolean mDozing;
+    private boolean mIsActiveDreamLockscreenHosted;
     private final ScreenLifecycle mScreenLifecycle;
+    @VisibleForTesting
+    final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
+            (Boolean isLockscreenHosted) -> {
+                if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) {
+                    return;
+                }
+                mIsActiveDreamLockscreenHosted = isLockscreenHosted;
+                updateDeviceEntryIndication(false);
+            };
     private final ScreenLifecycle.Observer mScreenObserver =
             new ScreenLifecycle.Observer() {
         @Override
@@ -261,7 +275,8 @@
             UserTracker userTracker,
             BouncerMessageInteractor bouncerMessageInteractor,
             FeatureFlags flags,
-            IndicationHelper indicationHelper
+            IndicationHelper indicationHelper,
+            KeyguardInteractor keyguardInteractor
     ) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
@@ -289,6 +304,7 @@
         mBouncerMessageInteractor = bouncerMessageInteractor;
         mFeatureFlags = flags;
         mIndicationHelper = indicationHelper;
+        mKeyguardInteractor = keyguardInteractor;
 
         mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
         mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
@@ -371,6 +387,10 @@
             intentFilter.addAction(Intent.ACTION_USER_REMOVED);
             mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter);
         }
+        if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
+            collectFlow(mIndicationArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
+                    mIsActiveDreamLockscreenHostedCallback);
+        }
     }
 
     /**
@@ -878,6 +898,12 @@
             return;
         }
 
+        // Device is dreaming and the dream is hosted in lockscreen
+        if (mIsActiveDreamLockscreenHosted) {
+            mIndicationArea.setVisibility(GONE);
+            return;
+        }
+
         // A few places might need to hide the indication, so always start by making it visible
         mIndicationArea.setVisibility(VISIBLE);
 
@@ -1069,6 +1095,7 @@
         pw.println("  mBiometricMessageFollowUp: " + mBiometricMessageFollowUp);
         pw.println("  mBatteryLevel: " + mBatteryLevel);
         pw.println("  mBatteryPresent: " + mBatteryPresent);
+        pw.println("  mIsActiveDreamLockscreenHosted: " + mIsActiveDreamLockscreenHosted);
         pw.println("  AOD text: " + (
                 mTopIndicationView == null ? null : mTopIndicationView.getText()));
         pw.println("  computePowerIndication(): " + computePowerIndication());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
new file mode 100644
index 0000000..ac04bc4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -0,0 +1,210 @@
+/*
+ * 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.keyguard;
+
+import static android.view.View.INVISIBLE;
+
+import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.ClockAnimations;
+import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.ClockEvents;
+import com.android.systemui.plugins.ClockFaceConfig;
+import com.android.systemui.plugins.ClockFaceController;
+import com.android.systemui.plugins.ClockFaceEvents;
+import com.android.systemui.plugins.ClockTickRate;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.clocks.AnimatableClockView;
+import com.android.systemui.shared.clocks.ClockRegistry;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
+
+    @Mock
+    protected KeyguardClockSwitch mView;
+    @Mock
+    protected StatusBarStateController mStatusBarStateController;
+    @Mock
+    protected ClockRegistry mClockRegistry;
+    @Mock
+    KeyguardSliceViewController mKeyguardSliceViewController;
+    @Mock
+    NotificationIconAreaController mNotificationIconAreaController;
+    @Mock
+    LockscreenSmartspaceController mSmartspaceController;
+
+    @Mock
+    Resources mResources;
+    @Mock
+    KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    @Mock
+    protected ClockController mClockController;
+    @Mock
+    protected ClockFaceController mLargeClockController;
+    @Mock
+    protected ClockFaceController mSmallClockController;
+    @Mock
+    protected ClockAnimations mClockAnimations;
+    @Mock
+    protected ClockEvents mClockEvents;
+    @Mock
+    protected ClockFaceEvents mClockFaceEvents;
+    @Mock
+    DumpManager mDumpManager;
+    @Mock
+    ClockEventController mClockEventController;
+
+    @Mock
+    protected NotificationIconContainer mNotificationIcons;
+    @Mock
+    protected AnimatableClockView mSmallClockView;
+    @Mock
+    protected AnimatableClockView mLargeClockView;
+    @Mock
+    protected FrameLayout mSmallClockFrame;
+    @Mock
+    protected FrameLayout mLargeClockFrame;
+    @Mock
+    protected SecureSettings mSecureSettings;
+    @Mock
+    protected LogBuffer mLogBuffer;
+
+    protected final View mFakeDateView = (View) (new ViewGroup(mContext) {
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {}
+    });
+    protected final View mFakeWeatherView = new View(mContext);
+    protected final View mFakeSmartspaceView = new View(mContext);
+
+    protected KeyguardClockSwitchController mController;
+    protected View mSliceView;
+    protected LinearLayout mStatusArea;
+    protected FakeExecutor mExecutor;
+    protected FakeFeatureFlags mFakeFeatureFlags;
+    @Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
+            ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mView.findViewById(R.id.left_aligned_notification_icon_container))
+                .thenReturn(mNotificationIcons);
+        when(mNotificationIcons.getLayoutParams()).thenReturn(
+                mock(RelativeLayout.LayoutParams.class));
+        when(mView.getContext()).thenReturn(getContext());
+        when(mView.getResources()).thenReturn(mResources);
+        when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
+                .thenReturn(100);
+        when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
+                .thenReturn(-200);
+        when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
+                .thenReturn(INVISIBLE);
+
+        when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
+        when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
+        when(mSmallClockView.getContext()).thenReturn(getContext());
+        when(mLargeClockView.getContext()).thenReturn(getContext());
+
+        when(mView.isAttachedToWindow()).thenReturn(true);
+        when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
+        when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
+        when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
+        mExecutor = new FakeExecutor(new FakeSystemClock());
+        mFakeFeatureFlags = new FakeFeatureFlags();
+        mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
+        mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
+        mController = new KeyguardClockSwitchController(
+                mView,
+                mStatusBarStateController,
+                mClockRegistry,
+                mKeyguardSliceViewController,
+                mNotificationIconAreaController,
+                mSmartspaceController,
+                mKeyguardUnlockAnimationController,
+                mSecureSettings,
+                mExecutor,
+                mDumpManager,
+                mClockEventController,
+                mLogBuffer,
+                KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
+                mFakeFeatureFlags
+        );
+
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+        when(mLargeClockController.getView()).thenReturn(mLargeClockView);
+        when(mSmallClockController.getView()).thenReturn(mSmallClockView);
+        when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
+        when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
+        when(mClockController.getEvents()).thenReturn(mClockEvents);
+        when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
+        when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
+        when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
+        when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
+        when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
+        when(mClockEventController.getClock()).thenReturn(mClockController);
+        when(mSmallClockController.getConfig())
+                .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
+        when(mLargeClockController.getConfig())
+                .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
+
+        mSliceView = new View(getContext());
+        when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
+        mStatusArea = new LinearLayout(getContext());
+        when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
+    }
+
+    protected void init() {
+        mController.init();
+
+        verify(mView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
+        mAttachCaptor.getValue().onViewAttachedToWindow(mView);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 9e561ed..e64ef04 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -21,186 +21,33 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.plugins.ClockAnimations;
-import com.android.systemui.plugins.ClockController;
-import com.android.systemui.plugins.ClockEvents;
 import com.android.systemui.plugins.ClockFaceConfig;
-import com.android.systemui.plugins.ClockFaceController;
-import com.android.systemui.plugins.ClockFaceEvents;
 import com.android.systemui.plugins.ClockTickRate;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.clocks.AnimatableClockView;
 import com.android.systemui.shared.clocks.ClockRegistry;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.NotificationIconContainer;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
-import com.android.systemui.util.time.FakeSystemClock;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.mockito.verification.VerificationMode;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
-
-    @Mock
-    private KeyguardClockSwitch mView;
-    @Mock
-    private StatusBarStateController mStatusBarStateController;
-    @Mock
-    private ClockRegistry mClockRegistry;
-    @Mock
-    KeyguardSliceViewController mKeyguardSliceViewController;
-    @Mock
-    NotificationIconAreaController mNotificationIconAreaController;
-    @Mock
-    LockscreenSmartspaceController mSmartspaceController;
-
-    @Mock
-    Resources mResources;
-    @Mock
-    KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
-    @Mock
-    private ClockController mClockController;
-    @Mock
-    private ClockFaceController mLargeClockController;
-    @Mock
-    private ClockFaceController mSmallClockController;
-    @Mock
-    private ClockAnimations mClockAnimations;
-    @Mock
-    private ClockEvents mClockEvents;
-    @Mock
-    private ClockFaceEvents mClockFaceEvents;
-    @Mock
-    DumpManager mDumpManager;
-    @Mock
-    ClockEventController mClockEventController;
-
-    @Mock
-    private NotificationIconContainer mNotificationIcons;
-    @Mock
-    private AnimatableClockView mSmallClockView;
-    @Mock
-    private AnimatableClockView mLargeClockView;
-    @Mock
-    private FrameLayout mSmallClockFrame;
-    @Mock
-    private FrameLayout mLargeClockFrame;
-    @Mock
-    private SecureSettings mSecureSettings;
-    @Mock
-    private LogBuffer mLogBuffer;
-
-    private final View mFakeDateView = (View) (new ViewGroup(mContext) {
-        @Override
-        protected void onLayout(boolean changed, int l, int t, int r, int b) {}
-    });
-    private final View mFakeWeatherView = new View(mContext);
-    private final View mFakeSmartspaceView = new View(mContext);
-
-    private KeyguardClockSwitchController mController;
-    private View mSliceView;
-    private FakeExecutor mExecutor;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-
-        when(mView.findViewById(R.id.left_aligned_notification_icon_container))
-                .thenReturn(mNotificationIcons);
-        when(mNotificationIcons.getLayoutParams()).thenReturn(
-                mock(RelativeLayout.LayoutParams.class));
-        when(mView.getContext()).thenReturn(getContext());
-        when(mView.getResources()).thenReturn(mResources);
-        when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
-                .thenReturn(100);
-        when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
-                .thenReturn(-200);
-        when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
-                .thenReturn(View.INVISIBLE);
-
-        when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
-        when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
-        when(mSmallClockView.getContext()).thenReturn(getContext());
-        when(mLargeClockView.getContext()).thenReturn(getContext());
-
-        when(mView.isAttachedToWindow()).thenReturn(true);
-        when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
-        when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
-        when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
-        mExecutor = new FakeExecutor(new FakeSystemClock());
-        mController = new KeyguardClockSwitchController(
-                mView,
-                mStatusBarStateController,
-                mClockRegistry,
-                mKeyguardSliceViewController,
-                mNotificationIconAreaController,
-                mSmartspaceController,
-                mKeyguardUnlockAnimationController,
-                mSecureSettings,
-                mExecutor,
-                mDumpManager,
-                mClockEventController,
-                mLogBuffer
-        );
-
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
-        when(mLargeClockController.getView()).thenReturn(mLargeClockView);
-        when(mSmallClockController.getView()).thenReturn(mSmallClockView);
-        when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
-        when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
-        when(mClockController.getEvents()).thenReturn(mClockEvents);
-        when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
-        when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
-        when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
-        when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
-        when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
-        when(mClockEventController.getClock()).thenReturn(mClockController);
-        when(mSmallClockController.getConfig())
-                .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
-        when(mLargeClockController.getConfig())
-                .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
-
-        mSliceView = new View(getContext());
-        when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
-        when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(
-                new LinearLayout(getContext()));
-    }
-
+public class KeyguardClockSwitchControllerTest extends KeyguardClockSwitchControllerBaseTest {
     @Test
     public void testInit_viewAlreadyAttached() {
         mController.init();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
new file mode 100644
index 0000000..9a1a4e2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class KeyguardClockSwitchControllerWithCoroutinesTest : KeyguardClockSwitchControllerBaseTest() {
+
+    @Test
+    fun testStatusAreaVisibility_onLockscreenHostedDreamStateChanged() =
+        runBlocking(IMMEDIATE) {
+            // GIVEN starting state for the keyguard clock and wallpaper dream enabled
+            mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
+            init()
+
+            // WHEN dreaming starts
+            mController.mIsActiveDreamLockscreenHostedCallback.accept(
+                true /* isActiveDreamLockscreenHosted */
+            )
+
+            // THEN the status area is hidden
+            mExecutor.runAllReady()
+            assertEquals(View.INVISIBLE, mStatusArea.visibility)
+
+            // WHEN dreaming stops
+            mController.mIsActiveDreamLockscreenHostedCallback.accept(
+                false /* isActiveDreamLockscreenHosted */
+            )
+            mExecutor.runAllReady()
+
+            // THEN status area view is visible
+            assertEquals(View.VISIBLE, mStatusArea.visibility)
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 75106e7..956e0b81 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -19,6 +19,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
 import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
 import static com.android.systemui.flags.Flags.MIGRATE_LOCK_ICON;
 
 import static org.mockito.Mockito.any;
@@ -147,6 +148,7 @@
         mFeatureFlags = new FakeFeatureFlags();
         mFeatureFlags.set(FACE_AUTH_REFACTOR, false);
         mFeatureFlags.set(MIGRATE_LOCK_ICON, false);
+        mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
         mUnderTest = new LockIconViewController(
                 mLockIconView,
                 mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
index d2c54b4..c372f45 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
@@ -17,9 +17,11 @@
 package com.android.keyguard
 
 import android.testing.AndroidTestingRunner
+import android.view.View
 import androidx.test.filters.SmallTest
 import com.android.keyguard.LockIconView.ICON_LOCK
 import com.android.systemui.doze.util.getBurnInOffset
+import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
@@ -117,6 +119,33 @@
             verify(mLockIconView).setTranslationX(0f)
         }
 
+    @Test
+    fun testHideLockIconView_onLockscreenHostedDreamStateChanged() =
+        runBlocking(IMMEDIATE) {
+            // GIVEN starting state for the lock icon (keyguard) and wallpaper dream enabled
+            mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
+            setupShowLockIcon()
+            init(/* useMigrationFlag= */ true)
+            reset(mLockIconView)
+
+            // WHEN dream starts
+            mUnderTest.mIsActiveDreamLockscreenHostedCallback.accept(
+                true /* isActiveDreamLockscreenHosted */
+            )
+
+            // THEN the lock icon is hidden
+            verify(mLockIconView).visibility = View.INVISIBLE
+            reset(mLockIconView)
+
+            // WHEN the device is no longer dreaming
+            mUnderTest.mIsActiveDreamLockscreenHostedCallback.accept(
+                false /* isActiveDreamLockscreenHosted */
+            )
+
+            // THEN lock icon is visible
+            verify(mLockIconView).visibility = View.VISIBLE
+        }
+
     companion object {
         private val IMMEDIATE = Dispatchers.Main.immediate
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
new file mode 100644
index 0000000..d44846e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+
+import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
+import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.Instrumentation;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
+import android.app.trust.TrustManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Looper;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.testing.TestableLooper;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.FaceHelpMessageDeferral;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.keyguard.KeyguardIndication;
+import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.keyguard.util.IndicationHelper;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.wakelock.WakeLockFake;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class KeyguardIndicationControllerBaseTest extends SysuiTestCase {
+
+    protected static final String ORGANIZATION_NAME = "organization";
+
+    protected static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName(
+            "com.android.foo",
+            "bar");
+
+    protected static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
+
+    protected String mDisclosureWithOrganization;
+    protected String mDisclosureGeneric;
+    protected String mFinancedDisclosureWithOrganization;
+
+    @Mock
+    protected DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    protected DevicePolicyResourcesManager mDevicePolicyResourcesManager;
+    @Mock
+    protected ViewGroup mIndicationArea;
+    @Mock
+    protected KeyguardStateController mKeyguardStateController;
+    @Mock
+    protected KeyguardIndicationTextView mIndicationAreaBottom;
+    @Mock
+    protected BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    protected StatusBarStateController mStatusBarStateController;
+    @Mock
+    protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock
+    protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock
+    protected UserManager mUserManager;
+    @Mock
+    protected IBatteryStats mIBatteryStats;
+    @Mock
+    protected DockManager mDockManager;
+    @Mock
+    protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
+    @Mock
+    protected FalsingManager mFalsingManager;
+    @Mock
+    protected LockPatternUtils mLockPatternUtils;
+    @Mock
+    protected KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    protected AccessibilityManager mAccessibilityManager;
+    @Mock
+    protected FaceHelpMessageDeferral mFaceHelpMessageDeferral;
+    @Mock
+    protected AlternateBouncerInteractor mAlternateBouncerInteractor;
+    @Mock
+    protected ScreenLifecycle mScreenLifecycle;
+    @Mock
+    protected AuthController mAuthController;
+    @Mock
+    protected AlarmManager mAlarmManager;
+    @Mock
+    protected UserTracker mUserTracker;
+    @Captor
+    protected ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
+    @Captor
+    protected ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
+    @Captor
+    protected ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+    @Captor
+    protected ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
+    @Captor
+    protected ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
+    @Captor
+    protected ArgumentCaptor<KeyguardStateController.Callback>
+            mKeyguardStateControllerCallbackCaptor;
+    @Captor
+    protected ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
+    protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
+    protected KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+    protected StatusBarStateController.StateListener mStatusBarStateListener;
+    protected ScreenLifecycle.Observer mScreenObserver;
+    protected BroadcastReceiver mBroadcastReceiver;
+    protected IndicationHelper mIndicationHelper;
+    protected FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+    protected TestableLooper mTestableLooper;
+    protected final int mCurrentUserId = 1;
+
+    protected KeyguardIndicationTextView mTextView; // AOD text
+
+    protected KeyguardIndicationController mController;
+    protected WakeLockFake.Builder mWakeLockBuilder;
+    protected WakeLockFake mWakeLock;
+    protected Instrumentation mInstrumentation;
+    protected FakeFeatureFlags mFlags;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mTestableLooper = TestableLooper.get(this);
+        mTextView = new KeyguardIndicationTextView(mContext);
+        mTextView.setAnimationsEnabled(false);
+
+        // TODO(b/259908270): remove
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+                DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
+                /* makeDefault= */ false);
+        mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
+        mContext.addMockSystemService(UserManager.class, mUserManager);
+        mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
+        mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
+        mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
+                ORGANIZATION_NAME);
+        mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
+        mFinancedDisclosureWithOrganization = mContext.getString(
+                R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
+
+        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+        when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON);
+        when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
+
+        when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
+                .thenReturn(mIndicationAreaBottom);
+        when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
+
+        when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
+        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+                .thenReturn(DEVICE_OWNER_COMPONENT);
+        when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
+        // TODO(b/259908270): remove
+        when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+                .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
+
+        when(mDevicePolicyResourcesManager.getString(anyString(), any()))
+                .thenReturn(mDisclosureGeneric);
+        when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
+                .thenReturn(mDisclosureWithOrganization);
+        when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
+
+        mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
+
+        mWakeLock = new WakeLockFake();
+        mWakeLockBuilder = new WakeLockFake.Builder(mContext);
+        mWakeLockBuilder.setWakeLock(mWakeLock);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTextView.setAnimationsEnabled(true);
+        if (mController != null) {
+            mController.destroy();
+            mController = null;
+        }
+    }
+
+    protected void createController() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mFlags = new FakeFeatureFlags();
+        mFlags.set(KEYGUARD_TALKBACK_FIX, true);
+        mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
+        mFlags.set(FACE_AUTH_REFACTOR, false);
+        mController = new KeyguardIndicationController(
+                mContext,
+                mTestableLooper.getLooper(),
+                mWakeLockBuilder,
+                mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
+                mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
+                mUserManager, mExecutor, mExecutor, mFalsingManager,
+                mAuthController, mLockPatternUtils, mScreenLifecycle,
+                mKeyguardBypassController, mAccessibilityManager,
+                mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
+                mAlternateBouncerInteractor,
+                mAlarmManager,
+                mUserTracker,
+                mock(BouncerMessageInteractor.class),
+                mFlags,
+                mIndicationHelper,
+                KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor()
+        );
+        mController.init();
+        mController.setIndicationArea(mIndicationArea);
+        verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
+        mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
+        verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
+        mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+        mController.mRotateTextViewController = mRotateTextViewController;
+        mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+        clearInvocations(mIBatteryStats);
+
+        verify(mKeyguardStateController).addCallback(
+                mKeyguardStateControllerCallbackCaptor.capture());
+        mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
+
+        verify(mKeyguardUpdateMonitor).registerCallback(
+                mKeyguardUpdateMonitorCallbackCaptor.capture());
+        mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
+
+        verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
+        mScreenObserver = mScreenObserverCaptor.getValue();
+
+        mExecutor.runAllReady();
+        reset(mRotateTextViewController);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index b1f5dde..8cf005dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -11,12 +11,11 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.systemui.statusbar;
 
-import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
@@ -26,7 +25,6 @@
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
-import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
@@ -38,7 +36,6 @@
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_OFF;
-import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_TURNING_ON;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -60,73 +57,28 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.app.AlarmManager;
-import android.app.Instrumentation;
-import android.app.admin.DevicePolicyManager;
-import android.app.admin.DevicePolicyResourcesManager;
-import android.app.trust.TrustManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.fingerprint.FingerprintManager;
 import android.os.BatteryManager;
-import android.os.Looper;
 import android.os.RemoteException;
-import android.os.UserManager;
-import android.provider.DeviceConfig;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.TrustGrantFlags;
-import com.android.keyguard.logging.KeyguardLogger;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.biometrics.FaceHelpMessageDeferral;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
-import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.keyguard.KeyguardIndication;
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.util.IndicationHelper;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.wakelock.WakeLockFake;
 
-import org.junit.After;
-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.MockitoAnnotations;
 
 import java.text.NumberFormat;
 import java.util.Collections;
@@ -137,205 +89,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class KeyguardIndicationControllerTest extends SysuiTestCase {
-
-    private static final String ORGANIZATION_NAME = "organization";
-
-    private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
-            "bar");
-
-    private static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
-
-    private String mDisclosureWithOrganization;
-    private String mDisclosureGeneric;
-    private String mFinancedDisclosureWithOrganization;
-
-    @Mock
-    private DevicePolicyManager mDevicePolicyManager;
-    @Mock
-    private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
-    @Mock
-    private ViewGroup mIndicationArea;
-    @Mock
-    private KeyguardStateController mKeyguardStateController;
-    @Mock
-    private KeyguardIndicationTextView mIndicationAreaBottom;
-    @Mock
-    private BroadcastDispatcher mBroadcastDispatcher;
-    @Mock
-    private StatusBarStateController mStatusBarStateController;
-    @Mock
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    @Mock
-    private UserManager mUserManager;
-    @Mock
-    private IBatteryStats mIBatteryStats;
-    @Mock
-    private DockManager mDockManager;
-    @Mock
-    private KeyguardIndicationRotateTextViewController mRotateTextViewController;
-    @Mock
-    private FalsingManager mFalsingManager;
-    @Mock
-    private LockPatternUtils mLockPatternUtils;
-    @Mock
-    private KeyguardBypassController mKeyguardBypassController;
-    @Mock
-    private AccessibilityManager mAccessibilityManager;
-    @Mock
-    private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
-    @Mock
-    private AlternateBouncerInteractor mAlternateBouncerInteractor;
-    @Mock
-    private ScreenLifecycle mScreenLifecycle;
-    @Mock
-    private AuthController mAuthController;
-    @Mock
-    private AlarmManager mAlarmManager;
-    @Mock
-    private UserTracker mUserTracker;
-    @Captor
-    private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
-    @Captor
-    private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
-    @Captor
-    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
-    @Captor
-    private ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
-    @Captor
-    private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
-    @Captor
-    private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
-    @Captor
-    private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
-    private KeyguardStateController.Callback mKeyguardStateControllerCallback;
-    private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
-    private StatusBarStateController.StateListener mStatusBarStateListener;
-    private ScreenLifecycle.Observer mScreenObserver;
-    private BroadcastReceiver mBroadcastReceiver;
-    private IndicationHelper mIndicationHelper;
-    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
-    private TestableLooper mTestableLooper;
-    private final int mCurrentUserId = 1;
-
-    private KeyguardIndicationTextView mTextView; // AOD text
-
-    private KeyguardIndicationController mController;
-    private WakeLockFake.Builder mWakeLockBuilder;
-    private WakeLockFake mWakeLock;
-    private Instrumentation mInstrumentation;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mTestableLooper = TestableLooper.get(this);
-        mTextView = new KeyguardIndicationTextView(mContext);
-        mTextView.setAnimationsEnabled(false);
-
-        // TODO(b/259908270): remove
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
-                DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
-                /* makeDefault= */ false);
-        mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
-        mContext.addMockSystemService(UserManager.class, mUserManager);
-        mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
-        mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
-        mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
-                ORGANIZATION_NAME);
-        mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
-        mFinancedDisclosureWithOrganization = mContext.getString(
-                R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
-
-        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
-        when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON);
-        when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
-
-        when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
-                .thenReturn(mIndicationAreaBottom);
-        when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
-
-        when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
-        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
-                .thenReturn(DEVICE_OWNER_COMPONENT);
-        when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
-        // TODO(b/259908270): remove
-        when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
-                .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
-
-        when(mDevicePolicyResourcesManager.getString(anyString(), any()))
-                .thenReturn(mDisclosureGeneric);
-        when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
-                .thenReturn(mDisclosureWithOrganization);
-        when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
-
-        mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
-
-        mWakeLock = new WakeLockFake();
-        mWakeLockBuilder = new WakeLockFake.Builder(mContext);
-        mWakeLockBuilder.setWakeLock(mWakeLock);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mTextView.setAnimationsEnabled(true);
-        if (mController != null) {
-            mController.destroy();
-            mController = null;
-        }
-    }
-
-    private void createController() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
-        FakeFeatureFlags flags = new FakeFeatureFlags();
-        flags.set(KEYGUARD_TALKBACK_FIX, true);
-        mController = new KeyguardIndicationController(
-                mContext,
-                mTestableLooper.getLooper(),
-                mWakeLockBuilder,
-                mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
-                mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
-                mUserManager, mExecutor, mExecutor, mFalsingManager,
-                mAuthController, mLockPatternUtils, mScreenLifecycle,
-                mKeyguardBypassController, mAccessibilityManager,
-                mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
-                mAlternateBouncerInteractor,
-                mAlarmManager,
-                mUserTracker,
-                mock(BouncerMessageInteractor.class),
-                flags,
-                mIndicationHelper
-        );
-        mController.init();
-        mController.setIndicationArea(mIndicationArea);
-        verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
-        mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
-        verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
-        mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
-        mController.mRotateTextViewController = mRotateTextViewController;
-        mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
-        clearInvocations(mIBatteryStats);
-
-        verify(mKeyguardStateController).addCallback(
-                mKeyguardStateControllerCallbackCaptor.capture());
-        mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
-
-        verify(mKeyguardUpdateMonitor).registerCallback(
-                mKeyguardUpdateMonitorCallbackCaptor.capture());
-        mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
-
-        verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
-        mScreenObserver = mScreenObserverCaptor.getValue();
-
-        mExecutor.runAllReady();
-        reset(mRotateTextViewController);
-    }
-
+public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
     @Test
     public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
         // GIVEN a controller with a mocked rotate text view controlller
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
new file mode 100644
index 0000000..cdc7520
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class KeyguardIndicationControllerWithCoroutinesTest : KeyguardIndicationControllerBaseTest() {
+    @Test
+    fun testIndicationAreaVisibility_onLockscreenHostedDreamStateChanged() =
+        runBlocking(IMMEDIATE) {
+            // GIVEN starting state for keyguard indication and wallpaper dream enabled
+            createController()
+            mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
+            mController.setVisible(true)
+
+            // THEN indication area is visible
+            verify(mIndicationArea, times(2)).visibility = View.VISIBLE
+
+            // WHEN the device is dreaming with lockscreen hosted dream
+            mController.mIsActiveDreamLockscreenHostedCallback.accept(
+                true /* isActiveDreamLockscreenHosted */
+            )
+            mExecutor.runAllReady()
+
+            // THEN the indication area is hidden
+            verify(mIndicationArea).visibility = View.GONE
+
+            // WHEN the device stops dreaming with lockscreen hosted dream
+            mController.mIsActiveDreamLockscreenHostedCallback.accept(
+                false /* isActiveDreamLockscreenHosted */
+            )
+            mExecutor.runAllReady()
+
+            // THEN indication area is set visible
+            verify(mIndicationArea, times(3)).visibility = View.VISIBLE
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}