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

Commit 5a9d80ee authored by Josh Tsuji's avatar Josh Tsuji
Browse files

Fix LsSceneTransitionInteractor's handling of canceled overlay transitions.

LsSceneTransitionInteractor was sending us to LOCKSCREEN if we canceled a Bouncer -> Lockscreen transition and returned to Bouncer, since it was only looking at our FINISHED transition to Scenes.Lockscreen.

This fixes the issue where UDFPS is touchable over Bouncer, but probably fixes some other things as well. I'm actually very surprised that KTF being in LOCKSCREEN while Bouncer is showing works as well as it does.

Bug: 444041956
Test: atest LockscreenSceneTransitionInteractorTest
Flag: com.android.systemui.scene_container
Change-Id: I8b303bc32b20d5d08b0582d35dd32454bd3dbd39
parent a9322002
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ 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.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.realKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -39,12 +40,14 @@ import kotlin.test.Test
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableSceneContainer
class LockscreenSceneTransitionInteractorTest : SysuiTestCase() {
    private val kosmos =
        testKosmos().apply { keyguardTransitionRepository = realKeyguardTransitionRepository }
@@ -1397,6 +1400,88 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() {
            )
        }

    /**
     * Transition from Bouncer to Lockscreen which is canceled, returning to Bouncer.
     *
     * We need to ensure that despite technically finishing a transition to Scenes.Lockscreen, we
     * return to UNDEFINED since the Bouncer overlay remained visible.
     */
    @Test
    fun canceledTransitionFromBouncerToLockscreen_returnsToUndefined() =
        testScope.runTest {
            val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions)
            sceneTransitions.value = goneToLs
            runCurrent()

            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
            runCurrent()

            sceneTransitions.value =
                ObservableTransitionState.Transition.ShowOrHideOverlay(
                    overlay = Overlays.Bouncer,
                    fromContent = Scenes.Lockscreen,
                    toContent = Overlays.Bouncer,
                    currentScene = Scenes.Lockscreen,
                    currentOverlays = flowOf(emptySet()),
                    progress,
                    isInitiatedByUserInput = false,
                    isUserInputOngoing = flowOf(false),
                    previewProgress = flowOf(0f),
                    isInPreviewStage = flowOf(false),
                )
            runCurrent()

            // Idle on Lockscreen with Bouncer showing.
            sceneTransitions.value =
                ObservableTransitionState.Idle(Scenes.Lockscreen, setOf(Overlays.Bouncer))
            runCurrent()

            assertTransition(
                step = currentStep!!,
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.UNDEFINED,
                state = TransitionState.FINISHED,
            )

            // Start hiding Bouncer.
            progress.value = 0.4f
            sceneTransitions.value =
                ObservableTransitionState.Transition.ShowOrHideOverlay(
                    overlay = Overlays.Bouncer,
                    fromContent = Overlays.Bouncer,
                    toContent = Scenes.Lockscreen,
                    currentScene = Scenes.Lockscreen,
                    currentOverlays = flowOf(setOf(Overlays.Bouncer)),
                    progress,
                    isInitiatedByUserInput = false,
                    isUserInputOngoing = flowOf(false),
                    previewProgress = flowOf(0f),
                    isInPreviewStage = flowOf(false),
                )
            runCurrent()

            assertTransition(
                step = currentStep!!,
                from = KeyguardState.UNDEFINED,
                to = KeyguardState.LOCKSCREEN,
                state = TransitionState.RUNNING,
                progress = 0.4f,
            )

            // Go back to Bouncer.
            sceneTransitions.value =
                ObservableTransitionState.Idle(Scenes.Lockscreen, setOf(Overlays.Bouncer))
            runCurrent()

            assertTransition(
                step = currentStep!!,
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.UNDEFINED,
                state = TransitionState.FINISHED,
                progress = 1f,
            )
        }

    private fun assertTransition(
        step: TransitionStep,
        from: KeyguardState? = null,
+10 −1
Original line number Diff line number Diff line
@@ -111,8 +111,17 @@ constructor(
        if (currentTransitionId == null) return
        if (prevTransition !is ObservableTransitionState.Transition) return

        // If the previous transition's fromContent is still in currentOverlays, we canceled a
        // transition away from that overlay.
        val canceledOverlayTransition = idle.currentOverlays.contains(prevTransition.fromContent)

        val idleOnToContentAfterCompletedTransition =
            idle.currentScene == prevTransition.toContent && !canceledOverlayTransition

        // Finish the current transition if we've completed a scene transition to a new scene or a
        // new overlay.
        if (
            idle.currentScene == prevTransition.toContent ||
            idleOnToContentAfterCompletedTransition ||
                idle.currentOverlays.contains(prevTransition.toContent)
        ) {
            finishCurrentTransition()