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

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

Merge "[flexiglass] Remove Lockscreen scene from backstack when face unlocked" into main

parents 025f8b58 967518d7
Loading
Loading
Loading
Loading
+68 −9
Original line number Diff line number Diff line
@@ -2532,6 +2532,64 @@ class SceneContainerStartableTest : SysuiTestCase() {
            assertThat(isAlternateBouncerVisible).isFalse()
        }

    @Test
    fun replacesLockscreenSceneOnBackStack_whenFaceUnlocked_fromShade_noAlternateBouncer() =
        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()

            // Simulate race condition by hiding the alternate bouncer *before* the face unlock:
            kosmos.alternateBouncerInteractor.hide()
            runCurrent()
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
            assertThat(isAlternateBouncerVisible).isFalse()

            // Trigger a face unlock.
            updateFaceAuthStatus(isSuccess = 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,
@@ -2768,15 +2826,16 @@ class SceneContainerStartableTest : SysuiTestCase() {
    }

    private fun updateFaceAuthStatus(isSuccess: Boolean) {
        with(kosmos.fakeDeviceEntryFaceAuthRepository) {
            isAuthenticated.value = isSuccess
            setAuthenticationStatus(
                if (isSuccess) {
            kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
                    SuccessFaceAuthenticationStatus(
                        successResult = Mockito.mock(FaceManager.AuthenticationResult::class.java)
                    )
            )
                } else {
            kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
                    FailedFaceAuthenticationStatus()
                }
            )
        }
    }
+16 −9
Original line number Diff line number Diff line
@@ -430,8 +430,13 @@ constructor(
                                            "mechanism: ${deviceUnlockStatus.deviceUnlockSource}"
                                else -> null
                            }
                        // Not on lockscreen or bouncer, so remain in the current scene.
                        else -> null
                        // Not on lockscreen or bouncer, so remain in the current scene but since
                        // unlocked, replace the Lockscreen scene from the bottom of the navigation
                        // back stack with the Gone scene.
                        else -> {
                            replaceLockscreenSceneOnBackStack()
                            null
                        }
                    }
                }
                .collect { (targetSceneKey, loggingReason) ->
@@ -440,17 +445,19 @@ constructor(
        }
    }

    /** If the [Scenes.Lockscreen] is on the backstack, replaces it with [Scenes.Gone]. */
    /**
     * If the [Scenes.Lockscreen] is on the bottom of the navigation 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."
            }
            if (list.lastOrNull() == Scenes.Lockscreen) {
                list[list.size - 1] = Scenes.Gone
                sceneStackOf(*list.toTypedArray())
            } else {
                stack
            }
        }
    }