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

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

Merge "[flexiglass] Fixes...

Merge "[flexiglass] Fixes WindowManagerLockscreenVisibilityInteractor.lockscreenVisibility" into main
parents df9a41bf d907df2d
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
@@ -72,7 +71,6 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
    private val trustRepository by lazy { kosmos.fakeTrustRepository }
    private val sceneInteractor by lazy { kosmos.sceneInteractor }
    private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
    private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
    private val sceneContainerStartable by lazy { kosmos.sceneContainerStartable }
    private val sysuiStatusBarStateController by lazy { kosmos.sysuiStatusBarStateController }
    private lateinit var underTest: DeviceEntryInteractor
@@ -437,7 +435,9 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
    fun isDeviceEntered_unlockedWhileOnShade_emitsTrue() =
        testScope.runTest {
            val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
            val isDeviceEnteredDirectly by collectLastValue(underTest.isDeviceEnteredDirectly)
            assertThat(isDeviceEntered).isFalse()
            assertThat(isDeviceEnteredDirectly).isFalse()
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

@@ -445,19 +445,20 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
            switchToScene(Scenes.Shade)
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            // Simulating a "leave it open when the keyguard is hidden" which means the bouncer will
            // be
            // shown and successful authentication should take the user back to where they are, the
            // shade scene.
            // be shown and successful authentication should take the user back to where they are,
            // the shade scene.
            sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
            switchToScene(Scenes.Bouncer)
            assertThat(currentScene).isEqualTo(Scenes.Bouncer)

            assertThat(isDeviceEntered).isFalse()
            assertThat(isDeviceEnteredDirectly).isFalse()
            // Authenticate with PIN to unlock and dismiss the lockscreen:
            authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
            runCurrent()

            assertThat(isDeviceEntered).isTrue()
            assertThat(isDeviceEnteredDirectly).isFalse()
        }

    private fun TestScope.switchToScene(sceneKey: SceneKey) {
+51 −12
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.authentication.data.repository.FakeAuthenticationRep
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
@@ -34,10 +35,12 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.data.model.sceneStackOf
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
@@ -85,7 +88,7 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
    fun setUp() {
        // lazy value needs to be called here otherwise flow collection misbehaves
        underTest.value
        kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
        kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Lockscreen))
    }

    @Test
@@ -965,6 +968,47 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
            assertThat(lockscreenVisibility).isTrue()
        }

    @Test
    @EnableSceneContainer
    fun lockscreenVisibilityWithScenes_staysTrue_despiteEnteringIndirectly() =
        testScope.runTest {
            val isDeviceUnlocked by
                collectLastValue(
                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
                )
            assertThat(isDeviceUnlocked).isFalse()

            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
            assertThat(lockscreenVisibility).isTrue()

            kosmos.setSceneTransition(Idle(Scenes.Shade))
            kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
            kosmos.sceneBackInteractor.onSceneChange(from = Scenes.Lockscreen, to = Scenes.Shade)
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(lockscreenVisibility).isTrue()
            val sceneBackStack by collectLastValue(kosmos.sceneBackInteractor.backStack)
            assertThat(sceneBackStack?.asIterable()?.toList()).isEqualTo(listOf(Scenes.Lockscreen))

            val isDeviceEntered by collectLastValue(kosmos.deviceEntryInteractor.isDeviceEntered)
            val isDeviceEnteredDirectly by
                collectLastValue(kosmos.deviceEntryInteractor.isDeviceEnteredDirectly)
            runCurrent()
            assertThat(isDeviceEntered).isFalse()
            assertThat(isDeviceEnteredDirectly).isFalse()

            kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
            kosmos.sceneBackInteractor.updateBackStack { sceneStackOf(Scenes.Gone) }
            assertThat(sceneBackStack?.asIterable()?.toList()).isEqualTo(listOf(Scenes.Gone))

            assertThat(isDeviceEntered).isTrue()
            assertThat(isDeviceEnteredDirectly).isFalse()
            assertThat(isDeviceUnlocked).isTrue()
            assertThat(lockscreenVisibility).isTrue()
        }

    @Test
    @EnableSceneContainer
    fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() =
@@ -972,10 +1016,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
            val usingKeyguardGoingAwayAnimation by
                collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)

            sceneTransitions.value = lsToGone
            kosmos.setSceneTransition(lsToGone)
            assertThat(usingKeyguardGoingAwayAnimation).isTrue()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
            kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone))
            assertThat(usingKeyguardGoingAwayAnimation).isFalse()
        }

@@ -986,14 +1030,14 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
            val usingKeyguardGoingAwayAnimation by
                collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)

            sceneTransitions.value = lsToGone
            kosmos.setSceneTransition(lsToGone)
            surfaceBehindIsAnimatingFlow.emit(true)
            assertThat(usingKeyguardGoingAwayAnimation).isTrue()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
            kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone))
            assertThat(usingKeyguardGoingAwayAnimation).isTrue()

            sceneTransitions.value = goneToLs
            kosmos.setSceneTransition(goneToLs)
            assertThat(usingKeyguardGoingAwayAnimation).isTrue()

            surfaceBehindIsAnimatingFlow.emit(false)
@@ -1003,11 +1047,6 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
    companion object {
        private val progress = MutableStateFlow(0f)

        private val sceneTransitions =
            MutableStateFlow<ObservableTransitionState>(
                ObservableTransitionState.Idle(Scenes.Lockscreen)
            )

        private val lsToGone =
            ObservableTransitionState.Transition(
                Scenes.Lockscreen,
+37 −14
Original line number Diff line number Diff line
@@ -84,16 +84,16 @@ constructor(
            )

    /**
     * Whether the device has been entered (i.e. the lockscreen has been dismissed, by any method).
     * This can be `false` when the device is unlocked, e.g. when the user still needs to swipe away
     * the non-secure lockscreen, even though they've already authenticated.
     * Emits `true` when the current scene switches to [Scenes.Gone] for the first time after having
     * been on [Scenes.Lockscreen].
     *
     * Note: This does not imply that the lockscreen is visible or not.
     * Different from [isDeviceEntered] such that the current scene must actually go through
     * [Scenes.Gone] to produce a `true`. [isDeviceEntered] also takes into account the navigation
     * back stack and will produce a `true` value even when the current scene is still not
     * [Scenes.Gone] but the bottommost entry of the navigation back stack switched from
     * [Scenes.Lockscreen] to [Scenes.Gone] while the user is staring at another scene.
     */
    val isDeviceEntered: StateFlow<Boolean> =
        combine(
                // This flow emits true when the currentScene switches to Gone for the first time
                // after having been on Lockscreen.
    val isDeviceEnteredDirectly: StateFlow<Boolean> =
        sceneInteractor.currentScene
            .filter { currentScene ->
                currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
@@ -107,7 +107,30 @@ constructor(
                } else {
                    false
                }
                    },
            }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.Eagerly,
                initialValue = false,
            )

    /**
     * Whether the device has been entered (i.e. the lockscreen has been dismissed, by any method).
     * This can be `false` when the device is unlocked, e.g. when the user still needs to swipe away
     * the non-secure lockscreen, even though they've already authenticated.
     *
     * Note: This does not imply that the lockscreen is visible or not.
     *
     * Different from [isDeviceEnteredDirectly] such that the current scene doesn't actually have to
     * go through [Scenes.Gone] to produce a `true`. [isDeviceEnteredDirectly] doesn't take the
     * navigation back stack into account and will only produce a `true` value even when the current
     * scene is actually [Scenes.Gone].
     */
    val isDeviceEntered: StateFlow<Boolean> =
        combine(
                // This flow emits true when the currentScene switches to Gone for the first time
                // after having been on Lockscreen.
                isDeviceEnteredDirectly,
                // This flow emits true only if the bottom of the navigation back stack has been
                // switched from Lockscreen to Gone. In other words, only if the device was unlocked
                // while visiting at least one scene "above" the Lockscreen scene.
+7 −5
Original line number Diff line number Diff line
@@ -112,8 +112,10 @@ constructor(
            }
            .distinctUntilChanged()

    private val isDeviceEntered by lazy { deviceEntryInteractor.get().isDeviceEntered }
    private val isDeviceNotEntered by lazy { isDeviceEntered.map { !it } }
    private val isDeviceEnteredDirectly by lazy {
        deviceEntryInteractor.get().isDeviceEnteredDirectly
    }
    private val isDeviceNotEnteredDirectly by lazy { isDeviceEnteredDirectly.map { !it } }

    /**
     * Surface visibility, which is either determined by the default visibility when not
@@ -126,7 +128,7 @@ constructor(
                sceneInteractor.get().transitionState.flatMapLatestConflated { state ->
                    when {
                        state.isTransitioning(from = Scenes.Lockscreen, to = Scenes.Gone) ->
                            isDeviceEntered
                            isDeviceEnteredDirectly
                        state.isTransitioning(from = Scenes.Bouncer, to = Scenes.Gone) ->
                            (state as Transition).progress.map { progress ->
                                progress >
@@ -210,7 +212,7 @@ constructor(
                            when (it.currentScene) {
                                in keyguardScenes -> flowOf(true)
                                in nonKeyguardScenes -> flowOf(false)
                                in keyguardAgnosticScenes -> isDeviceNotEntered
                                in keyguardAgnosticScenes -> isDeviceNotEnteredDirectly
                                else ->
                                    throw IllegalStateException("Unknown scene: ${it.currentScene}")
                            }
@@ -220,7 +222,7 @@ constructor(
                                it.isTransitioningSets(from = keyguardScenes) -> flowOf(true)
                                it.isTransitioningSets(from = nonKeyguardScenes) -> flowOf(false)
                                it.isTransitioningSets(from = keyguardAgnosticScenes) ->
                                    isDeviceNotEntered
                                    isDeviceNotEnteredDirectly
                                else ->
                                    throw IllegalStateException("Unknown scene: ${it.fromContent}")
                            }