Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit def700f7 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Fixes alternate bouncer unlock." into main

parents 54357697 765f6a74
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.systemui.biometrics.data.repository.fingerprintPropertyReposi
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
import com.android.systemui.bouncer.shared.logging.BouncerUiEvent
import com.android.systemui.classifier.FalsingCollector
@@ -54,6 +55,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
import com.android.systemui.flags.EnableSceneContainer
@@ -114,6 +116,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
@@ -2356,6 +2359,58 @@ class SceneContainerStartableTest : SysuiTestCase() {
            assertThat(isLockscreenEnabled).isTrue()
        }

    @Test
    fun replacesLockscreenSceneOnBackStack_whenUnlockdViaAlternateBouncer_fromShade() =
        testScope.runTest {
            val transitionState =
                prepareState(
                    isDeviceUnlocked = false,
                    initialSceneKey = Scenes.Lockscreen,
                    authenticationMethod = AuthenticationMethodModel.Pin,
                )
            underTest.start()

            val isUnlocked by
                collectLastValue(
                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
                )
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val backStack by collectLastValue(sceneBackInteractor.backStack)
            val isAlternateBouncerVisible by
                collectLastValue(kosmos.alternateBouncerInteractor.isVisible)
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(isAlternateBouncerVisible).isFalse()

            // Change to shade.
            sceneInteractor.changeScene(Scenes.Shade, "")
            transitionState.value = ObservableTransitionState.Idle(Scenes.Shade)
            runCurrent()
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
            assertThat(isAlternateBouncerVisible).isFalse()

            // Show the alternate bouncer.
            kosmos.alternateBouncerInteractor.forceShow()
            kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open
            runCurrent()
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
            assertThat(isAlternateBouncerVisible).isTrue()

            // Trigger a fingerprint unlock.
            kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            runCurrent()
            assertThat(isUnlocked).isTrue()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Gone)
            assertThat(isAlternateBouncerVisible).isFalse()
        }

    private fun TestScope.emulateSceneTransition(
        transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
        toScene: SceneKey,
+16 −10
Original line number Diff line number Diff line
@@ -373,6 +373,7 @@ constructor(
                                    "device was unlocked with alternate bouncer showing" +
                                        " and shade didn't need to be left open"
                            } else {
                                replaceLockscreenSceneOnBackStack()
                                null
                            }
                        }
@@ -391,16 +392,7 @@ constructor(
                                val prevScene = previousScene.value
                                val targetScene = prevScene ?: Scenes.Gone
                                if (targetScene != Scenes.Gone) {
                                    sceneBackInteractor.updateBackStack { stack ->
                                        val list = stack.asIterable().toMutableList()
                                        check(list.last() == Scenes.Lockscreen) {
                                            "The bottommost/last SceneKey of the back stack isn't" +
                                                " the Lockscreen scene like expected. The back" +
                                                " stack is $stack."
                                        }
                                        list[list.size - 1] = Scenes.Gone
                                        sceneStackOf(*list.toTypedArray())
                                    }
                                    replaceLockscreenSceneOnBackStack()
                                }
                                targetScene to
                                    "device was unlocked with primary bouncer showing," +
@@ -435,6 +427,20 @@ constructor(
        }
    }

    /** If the [Scenes.Lockscreen] is on the backstack, replaces it with [Scenes.Gone]. */
    private fun replaceLockscreenSceneOnBackStack() {
        sceneBackInteractor.updateBackStack { stack ->
            val list = stack.asIterable().toMutableList()
            check(list.last() == Scenes.Lockscreen) {
                "The bottommost/last SceneKey of the back stack isn't" +
                    " the Lockscreen scene like expected. The back" +
                    " stack is $stack."
            }
            list[list.size - 1] = Scenes.Gone
            sceneStackOf(*list.toTypedArray())
        }
    }

    private fun handlePowerState() {
        applicationScope.launch {
            powerInteractor.detailedWakefulness.collect { wakefulness ->
+7 −0
Original line number Diff line number Diff line
@@ -520,6 +520,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
            mListenForCanShowAlternateBouncer.cancel(null);
        }
        mListenForCanShowAlternateBouncer = null;

        // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
        mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
                mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
@@ -568,6 +569,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    }

    private void consumeCanShowAlternateBouncer(boolean canShow) {
        if (SceneContainerFlag.isEnabled()) {
            // When the scene framework is enabled, the alternative bouncer is hidden from the scene
            // framework logic so there's no need for this logic here.
            return;
        }

        // Hack: this is required to fix issues where
        // KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never
        // reset. This is caused by usages of show()/forceShow() that only read this flow to set the