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

Commit daaa5675 authored by Andreas Miko's avatar Andreas Miko
Browse files

Fix WindowManagerLockscreenVisibility

Because KTF is not transitioning to GONE anymore we need to rewire the
datasource of WindowManagerLockscreenVisibilityInteractor to STL instead

Test: WindowManagerLockscreenVisibilityTest
Bug: b/330311871
Bug: b/336331743
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: I67a7dfcb6318027273b053c808ab86a3fafc824c
parent abafa2f8
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -74,6 +74,16 @@ sealed interface ObservableTransitionState {
         */
        val isUserInputOngoing: Flow<Boolean>,
    ) : ObservableTransitionState

    fun isIdle(scene: SceneKey?): Boolean {
        return this is Idle && (scene == null || this.currentScene == scene)
    }

    fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean {
        return this is Transition &&
            (from == null || this.fromScene == from) &&
            (to == null || this.toScene == to)
    }
}

/**
+78 −35
Original line number Diff line number Diff line
@@ -16,11 +16,16 @@

package com.android.systemui.keyguard.domain.interactor

import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,6 +47,7 @@ constructor(
    fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor,
    fromAlternateBouncerInteractor: FromAlternateBouncerTransitionInteractor,
    notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
    sceneInteractor: SceneInteractor,
) {
    private val defaultSurfaceBehindVisibility =
        transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible)
@@ -103,6 +109,25 @@ constructor(
     * animation. This is used to keep the RemoteAnimationTarget alive until we're done using it.
     */
    val usingKeyguardGoingAwayAnimation: Flow<Boolean> =
        if (SceneContainerFlag.isEnabled) {
            combine(
                    sceneInteractor.transitionState,
                    surfaceBehindInteractor.isAnimatingSurface,
                    notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
                ) { transition, isAnimatingSurface, isLaunchAnimationRunning ->
                    // Using the animation if we're animating it directly, or if the
                    // ActivityLaunchAnimator is in the process of animating it.
                    val isAnyAnimationRunning = isAnimatingSurface || isLaunchAnimationRunning
                    // We may still be animating the surface after the keyguard is fully GONE, since
                    // some animations (like the translation spring) are not tied directly to the
                    // transition step amount.
                    transition.isTransitioning(to = Scenes.Gone) ||
                        (isAnyAnimationRunning &&
                            (transition.isIdle(Scenes.Gone) ||
                                transition.isTransitioning(from = Scenes.Gone)))
                }
                .distinctUntilChanged()
        } else {
            combine(
                    transitionInteractor.isInTransitionToState(KeyguardState.GONE),
                    transitionInteractor.finishedKeyguardState,
@@ -115,9 +140,11 @@ constructor(
                    // We may still be animating the surface after the keyguard is fully GONE, since
                    // some animations (like the translation spring) are not tied directly to the
                    // transition step amount.
                isInTransitionToGone || (finishedState == KeyguardState.GONE && animationsRunning)
                    isInTransitionToGone ||
                        (finishedState == KeyguardState.GONE && animationsRunning)
                }
                .distinctUntilChanged()
        }

    /**
     * Whether the lockscreen is visible, from the Window Manager (WM) perspective.
@@ -127,6 +154,21 @@ constructor(
     * want to know if the AOD/clock/notifs/etc. are visible.
     */
    val lockscreenVisibility: Flow<Boolean> =
        if (SceneContainerFlag.isEnabled) {
            sceneInteractor.transitionState
                .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen))
                .map { (prevTransitionState, transitionState) ->
                    val isReturningToGoneAfterCancellation =
                        prevTransitionState.isTransitioning(from = Scenes.Gone) &&
                            transitionState.isTransitioning(to = Scenes.Gone)
                    val isNotOnGone =
                        !transitionState.isTransitioning(from = Scenes.Gone) &&
                            !transitionState.isIdle(Scenes.Gone)

                    isNotOnGone && !isReturningToGoneAfterCancellation
                }
                .distinctUntilChanged()
        } else {
            transitionInteractor.currentKeyguardState
                .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
                .map { (currentState, startedWithPrev) ->
@@ -141,14 +183,15 @@ constructor(
                        // By default, apply the lockscreen visibility of the current state.
                        KeyguardState.lockscreenVisibleInState(currentState)
                    } else {
                    // If we're transitioning to GONE after a prior canceled transition from GONE,
                    // then this is the camera launch transition from an asleep state back to GONE.
                    // We don't want to show the lockscreen since we're aborting the lock and going
                    // back to GONE.
                        // If we're transitioning to GONE after a prior canceled transition from
                        // GONE, then this is the camera launch transition from an asleep state back
                        // to GONE. We don't want to show the lockscreen since we're aborting the
                        // lock and going back to GONE.
                        KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
                    }
                }
                .distinctUntilChanged()
        }

    /**
     * Whether always-on-display (AOD) is visible when the lockscreen is visible, from window
+136 −9
Original line number Diff line number Diff line
@@ -18,20 +18,29 @@ package com.android.systemui.keyguard.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
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.repository.sceneContainerRepository
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@@ -57,14 +66,22 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
                .thenReturn(surfaceBehindIsAnimatingFlow)
        }

    private val underTest = kosmos.windowManagerLockscreenVisibilityInteractor
    private val underTest = lazy { kosmos.windowManagerLockscreenVisibilityInteractor }
    private val testScope = kosmos.testScope
    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository

    @Before
    fun setUp() {
        // lazy value needs to be called here otherwise flow collection misbehaves
        underTest.value
        kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
    }

    @Test
    @DisableSceneContainer
    fun surfaceBehindVisibility_switchesToCorrectFlow() =
        testScope.runTest {
            val values by collectValues(underTest.surfaceBehindVisibility)
            val values by collectValues(underTest.value.surfaceBehindVisibility)

            // Start on LOCKSCREEN.
            transitionRepository.sendTransitionStep(
@@ -170,9 +187,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun testUsingGoingAwayAnimation_duringTransitionToGone() =
        testScope.runTest {
            val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
            val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation)

            // Start on LOCKSCREEN.
            transitionRepository.sendTransitionStep(
@@ -230,9 +248,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun testNotUsingGoingAwayAnimation_evenWhenAnimating_ifStateIsNotGone() =
        testScope.runTest {
            val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
            val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation)

            // Start on LOCKSCREEN.
            transitionRepository.sendTransitionStep(
@@ -319,9 +338,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun lockscreenVisibility_visibleWhenGone() =
        testScope.runTest {
            val values by collectValues(underTest.lockscreenVisibility)
            val values by collectValues(underTest.value.lockscreenVisibility)

            // Start on LOCKSCREEN.
            transitionRepository.sendTransitionStep(
@@ -385,9 +405,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun testLockscreenVisibility_usesFromState_ifCanceled() =
        testScope.runTest {
            val values by collectValues(underTest.lockscreenVisibility)
            val values by collectValues(underTest.value.lockscreenVisibility)

            transitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
@@ -486,9 +507,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
     * state during the AOD/isAsleep -> GONE transition is AOD (where lockscreen visibility = true).
     */
    @Test
    @DisableSceneContainer
    fun testLockscreenVisibility_falseDuringTransitionToGone_fromCanceledGone() =
        testScope.runTest {
            val values by collectValues(underTest.lockscreenVisibility)
            val values by collectValues(underTest.value.lockscreenVisibility)

            transitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
@@ -587,11 +609,11 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
            )
        }

    /**  */
    @Test
    @DisableSceneContainer
    fun testLockscreenVisibility_trueDuringTransitionToGone_fromNotCanceledGone() =
        testScope.runTest {
            val values by collectValues(underTest.lockscreenVisibility)
            val values by collectValues(underTest.value.lockscreenVisibility)

            transitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
@@ -702,4 +724,109 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
                values
            )
        }

    @Test
    @EnableSceneContainer
    fun sceneContainer_lockscreenVisibility_visibleWhenNotGone() =
        testScope.runTest {
            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)

            sceneTransitions.value = lsToGone
            assertThat(lockscreenVisibility).isTrue()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
            assertThat(lockscreenVisibility).isFalse()

            sceneTransitions.value = goneToLs
            assertThat(lockscreenVisibility).isFalse()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
            assertThat(lockscreenVisibility).isTrue()
        }

    @Test
    @EnableSceneContainer
    fun sceneContainer_lockscreenVisibility_notVisibleWhenReturningToGone() =
        testScope.runTest {
            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)

            sceneTransitions.value = goneToLs
            assertThat(lockscreenVisibility).isFalse()

            sceneTransitions.value = lsToGone
            assertThat(lockscreenVisibility).isFalse()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
            assertThat(lockscreenVisibility).isFalse()

            sceneTransitions.value = goneToLs
            assertThat(lockscreenVisibility).isFalse()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
            assertThat(lockscreenVisibility).isTrue()
        }

    @Test
    @EnableSceneContainer
    fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() =
        testScope.runTest {
            val usingKeyguardGoingAwayAnimation by
                collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)

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

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

    @Test
    @EnableSceneContainer
    fun sceneContainer_usingGoingAwayAnimation_surfaceBehindIsAnimating() =
        testScope.runTest {
            val usingKeyguardGoingAwayAnimation by
                collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)

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

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

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

            surfaceBehindIsAnimatingFlow.emit(false)
            assertThat(usingKeyguardGoingAwayAnimation).isFalse()
        }

    companion object {
        private val progress = MutableStateFlow(0f)

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

        private val lsToGone =
            ObservableTransitionState.Transition(
                Scenes.Lockscreen,
                Scenes.Gone,
                flowOf(Scenes.Lockscreen),
                progress,
                false,
                flowOf(false)
            )

        private val goneToLs =
            ObservableTransitionState.Transition(
                Scenes.Gone,
                Scenes.Lockscreen,
                flowOf(Scenes.Lockscreen),
                progress,
                false,
                flowOf(false)
            )
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -138,7 +138,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor

import com.android.systemui.kosmos.Kosmos
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor

val Kosmos.windowManagerLockscreenVisibilityInteractor by
@@ -29,5 +30,6 @@ val Kosmos.windowManagerLockscreenVisibilityInteractor by
            fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
            fromAlternateBouncerInteractor = fromAlternateBouncerTransitionInteractor,
            notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor,
            sceneInteractor = sceneInteractor,
        )
    }