Merge "Flexiglass: include alternate bouncer in status bar state calculation" into main
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 0e9ef06..0454317 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -22,6 +22,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -36,10 +40,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
 import android.animation.Animator;
 import android.annotation.IdRes;
 import android.content.ContentResolver;
@@ -201,6 +201,12 @@
 import com.android.systemui.util.time.SystemClock;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
+import dagger.Lazy;
+
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.channels.BufferOverflow;
+import kotlinx.coroutines.test.TestScope;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -215,11 +221,6 @@
 import java.util.List;
 import java.util.Optional;
 
-import dagger.Lazy;
-import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.channels.BufferOverflow;
-import kotlinx.coroutines.test.TestScope;
-
 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
 
     protected static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
@@ -461,7 +462,8 @@
                 () -> mKosmos.getSceneInteractor(),
                 () -> mKosmos.getSceneContainerOcclusionInteractor(),
                 () -> mKosmos.getKeyguardClockInteractor(),
-                () -> mKosmos.getSceneBackInteractor());
+                () -> mKosmos.getSceneBackInteractor(),
+                () -> mKosmos.getAlternateBouncerInteractor());
 
         KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
         keyguardStatusView.setId(R.id.keyguard_status_view);
@@ -622,7 +624,8 @@
                                 () -> mKosmos.getSceneInteractor(),
                                 () -> mKosmos.getSceneContainerOcclusionInteractor(),
                                 () -> mKosmos.getKeyguardClockInteractor(),
-                                () -> mKosmos.getSceneBackInteractor()),
+                                () -> mKosmos.getSceneBackInteractor(),
+                                () -> mKosmos.getAlternateBouncerInteractor()),
                         mKeyguardBypassController,
                         mDozeParameters,
                         mScreenOffAnimationController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index db274cc..f8720b4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -28,6 +28,8 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.givenCanShowAlternateBouncer
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.flags.DisableSceneContainer
@@ -83,8 +85,9 @@
 
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
-    private val sceneInteractor = kosmos.sceneInteractor
-    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+    private val sceneInteractor by lazy { kosmos.sceneInteractor }
+    private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+    private val alternateBouncerInteractor by lazy { kosmos.alternateBouncerInteractor }
     private val mockDarkAnimator = mock<ObjectAnimator>()
 
     private lateinit var underTest: StatusBarStateControllerImpl
@@ -121,6 +124,7 @@
                     { kosmos.sceneContainerOcclusionInteractor },
                     { kosmos.keyguardClockInteractor },
                     { kosmos.sceneBackInteractor },
+                    { kosmos.alternateBouncerInteractor },
                 ) {
                 override fun createDarkAnimator(): ObjectAnimator {
                     return mockDarkAnimator
@@ -299,6 +303,52 @@
 
     @Test
     @EnableSceneContainer
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun start_hydratesStatusBarState_withAlternateBouncer() =
+        testScope.runTest {
+            var statusBarState = underTest.state
+            val listener =
+                object : StatusBarStateController.StateListener {
+                    override fun onStateChanged(newState: Int) {
+                        statusBarState = newState
+                    }
+                }
+            underTest.addCallback(listener)
+
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val deviceUnlockStatus by
+                collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+            val alternateBouncerIsVisible by collectLastValue(alternateBouncerInteractor.isVisible)
+
+            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+                AuthenticationMethodModel.Password
+            )
+            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+                SuccessFingerprintAuthenticationStatus(0, true)
+            )
+            runCurrent()
+            assertThat(deviceUnlockStatus!!.isUnlocked).isTrue()
+
+            sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason")
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+            kosmos.givenCanShowAlternateBouncer()
+            alternateBouncerInteractor.forceShow()
+            runCurrent()
+            assertThat(alternateBouncerIsVisible).isTrue()
+
+            // Call start to begin hydrating based on the scene framework:
+            underTest.start()
+
+            sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason")
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
+        }
+
+    @Test
+    @EnableSceneContainer
     @EnableFlags(DualShade.FLAG_NAME)
     fun start_hydratesStatusBarState_dualShade_whileLocked() =
         testScope.runTest {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 73ad0e5..da04f6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -46,6 +46,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardClockSwitch;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor;
 import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus;
@@ -123,6 +124,7 @@
     private final Lazy<SceneContainerOcclusionInteractor> mSceneContainerOcclusionInteractorLazy;
     private final Lazy<KeyguardClockInteractor> mKeyguardClockInteractorLazy;
     private final Lazy<SceneBackInteractor> mSceneBackInteractorLazy;
+    private final Lazy<AlternateBouncerInteractor> mAlternateBouncerInteractorLazy;
     private int mState;
     private int mLastState;
     private int mUpcomingState;
@@ -193,7 +195,8 @@
             Lazy<SceneInteractor> sceneInteractorLazy,
             Lazy<SceneContainerOcclusionInteractor> sceneContainerOcclusionInteractor,
             Lazy<KeyguardClockInteractor> keyguardClockInteractorLazy,
-            Lazy<SceneBackInteractor> sceneBackInteractorLazy) {
+            Lazy<SceneBackInteractor> sceneBackInteractorLazy,
+            Lazy<AlternateBouncerInteractor> alternateBouncerInteractorLazy) {
         mUiEventLogger = uiEventLogger;
         mInteractionJankMonitorLazy = interactionJankMonitorLazy;
         mJavaAdapter = javaAdapter;
@@ -205,6 +208,7 @@
         mSceneContainerOcclusionInteractorLazy = sceneContainerOcclusionInteractor;
         mKeyguardClockInteractorLazy = keyguardClockInteractorLazy;
         mSceneBackInteractorLazy = sceneBackInteractorLazy;
+        mAlternateBouncerInteractorLazy = alternateBouncerInteractorLazy;
         for (int i = 0; i < HISTORY_SIZE; i++) {
             mHistoricalRecords[i] = new HistoricalState();
         }
@@ -233,6 +237,7 @@
                         mSceneInteractorLazy.get().getCurrentOverlays(),
                         mSceneBackInteractorLazy.get().getBackStack(),
                         mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(),
+                        mAlternateBouncerInteractorLazy.get().isVisible(),
                         this::calculateStateFromSceneFramework),
                     this::onStatusBarStateChanged);
 
@@ -693,7 +698,8 @@
             SceneKey currentScene,
             Set<OverlayKey> currentOverlays,
             SceneStack backStack,
-            boolean isOccluded) {
+            boolean isOccluded,
+            boolean alternateBouncerIsVisible) {
         SceneContainerFlag.isUnexpectedlyInLegacyMode();
 
         final boolean onBouncer = currentScene.equals(Scenes.Bouncer);
@@ -714,7 +720,8 @@
 
         final String inputLogString = "currentScene=" + currentScene.getTestTag()
                 + " currentOverlays=" + currentOverlays + " backStack=" + backStack
-                + " isUnlocked=" + isUnlocked + " isOccluded=" + isOccluded;
+                + " isUnlocked=" + isUnlocked + " isOccluded=" + isOccluded
+                + " alternateBouncerIsVisible=" + alternateBouncerIsVisible;
 
         int newState;
 
@@ -722,6 +729,7 @@
         // 1. deviceUnlockStatus.isUnlocked changes from false to true.
         // 2. Lockscreen changes to Gone, either in currentScene or in backStack.
         // 3. Bouncer is removed from currentScene or backStack, if it was present.
+        // 4. the alternate bouncer is hidden, if it was visible.
         //
         // From this function's perspective, though, deviceUnlockStatus, currentScene, and backStack
         // each update separately, and the relative order of those updates is not well-defined. This
@@ -733,6 +741,7 @@
         // 1. deviceUnlockStatus.isUnlocked is false.
         // 2. currentScene is a keyguardish scene (Lockscreen, Bouncer, or Communal).
         // 3. backStack contains a keyguardish scene (Lockscreen or Communal).
+        // 4. the alternate bouncer is visible.
 
         final boolean onKeyguardish = onLockscreen || onBouncer || onCommunal;
         final boolean overKeyguardish = overLockscreen || overCommunal;
@@ -741,7 +750,7 @@
             // Occlusion is special; even though the device is still technically on the lockscreen,
             // the UI behaves as if it is unlocked.
             newState = StatusBarState.SHADE;
-        } else if (onKeyguardish || overKeyguardish) {
+        } else if (onKeyguardish || overKeyguardish || alternateBouncerIsVisible) {
             // We get here if we are on or over a keyguardish scene, even if isUnlocked is true; we
             // want to return SHADE_LOCKED or KEYGUARD until we are also neither on nor over a
             // keyguardish scene.
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index f97f303..522c387 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.bouncerRepository
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
 import com.android.systemui.classifier.falsingCollector
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
@@ -152,6 +153,7 @@
     val wifiInteractor by lazy { kosmos.wifiInteractor }
     val fakeWifiRepository by lazy { kosmos.fakeWifiRepository }
     val volumeDialogInteractor by lazy { kosmos.volumeDialogInteractor }
+    val alternateBouncerInteractor by lazy { kosmos.alternateBouncerInteractor }
 
     val ongoingActivityChipsViewModel by lazy { kosmos.ongoingActivityChipsViewModel }
     val scrimController by lazy { kosmos.scrimController }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
index cfc31c7..10b073e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.plugins.statusbar
 
 import com.android.internal.logging.uiEventLogger
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.jank.interactionJankMonitor
 import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
@@ -45,5 +46,6 @@
             { sceneContainerOcclusionInteractor },
             { keyguardClockInteractor },
             { sceneBackInteractor },
+            { alternateBouncerInteractor },
         )
     }