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

Commit e15aa948 authored by Alejandro Nijamkin's avatar Alejandro Nijamkin Committed by Ale Nijamkin
Browse files

[flexiglass] Adds support freezeAndAnimateToCurrentState

This way, a half-way done transition can revert-animate to the previous scene even if the transition is still ongoing.

Bug: 396191914
Test: manually verified that pulling up the bouncer or pulling down the
shade, keeping the finger down, and pressing the power button correctly
moves back to the Lockscreen scene and puts it in AOD mode
Test: manually verified transitions into and out of AOD still works when
on the lockscreen scene
Flag: com.android.systemui.scene_container

Change-Id: I0d17373864e89d85b8661c37d95cb295f75fadb2
parent b40a38c3
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.scene.shared.model.SceneDataSource
import kotlinx.coroutines.CoroutineScope
@@ -103,4 +104,8 @@ class SceneTransitionLayoutDataSource(
    override fun instantlyHideOverlay(overlay: OverlayKey) {
        state.snapTo(overlays = state.currentOverlays - overlay)
    }

    override fun freezeAndAnimateToCurrentState() {
        (state.transitionState as? TransitionState.Transition)?.freezeAndAnimateToCurrentState()
    }
}
+39 −0
Original line number Diff line number Diff line
@@ -1358,6 +1358,45 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() {
            )
        }

    /**
     * When a transition away from the lockscreen is interrupted by an `Idle(Lockscreen)`, a
     * `sceneState` that was set during the transition is consumed and passed to KTF.
     */
    @Test
    fun transition_from_ls_scene_sceneStateSet_then_interrupted_by_idle_on_ls() =
        testScope.runTest {
            val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions)
            sceneTransitions.value =
                ObservableTransitionState.Transition(
                    Scenes.Lockscreen,
                    Scenes.Gone,
                    flowOf(Scenes.Lockscreen),
                    progress,
                    false,
                    flowOf(false),
                )
            progress.value = 0.4f
            assertTransition(
                step = currentStep!!,
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.UNDEFINED,
                state = TransitionState.RUNNING,
                progress = 0.4f,
            )

            val sceneState = KeyguardState.AOD
            underTest.onSceneAboutToChange(toScene = Scenes.Lockscreen, sceneState = sceneState)
            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)

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

    private fun assertTransition(
        step: TransitionStep,
        from: KeyguardState? = null,
+42 −0
Original line number Diff line number Diff line
@@ -757,4 +757,46 @@ class SceneInteractorTest : SysuiTestCase() {

            verify(processor, never()).onSceneAboutToChange(any(), any())
        }

    @Test
    fun changeScene_sameScene_withFreeze() =
        kosmos.runTest {
            val currentScene by collectLastValue(underTest.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            val processor = mock<SceneInteractor.OnSceneAboutToChangeListener>()
            underTest.registerSceneStateProcessor(processor)
            verify(processor, never()).onSceneAboutToChange(any(), any())
            assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0)

            underTest.changeScene(
                toScene = Scenes.Lockscreen,
                loggingReason = "test",
                sceneState = KeyguardState.AOD,
                forceSettleToTargetScene = true,
            )

            verify(processor).onSceneAboutToChange(Scenes.Lockscreen, KeyguardState.AOD)
            assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(1)
        }

    @Test
    fun changeScene_sameScene_withoutFreeze() =
        kosmos.runTest {
            val currentScene by collectLastValue(underTest.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            val processor = mock<SceneInteractor.OnSceneAboutToChangeListener>()
            underTest.registerSceneStateProcessor(processor)
            verify(processor, never()).onSceneAboutToChange(any(), any())
            assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0)

            underTest.changeScene(
                toScene = Scenes.Lockscreen,
                loggingReason = "test",
                sceneState = KeyguardState.AOD,
                forceSettleToTargetScene = false,
            )

            verify(processor, never()).onSceneAboutToChange(any(), any())
            assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0)
        }
}
+2 −0
Original line number Diff line number Diff line
@@ -151,5 +151,7 @@ constructor(
        override fun instantlyShowOverlay(overlay: OverlayKey) = Unit

        override fun instantlyHideOverlay(overlay: OverlayKey) = Unit

        override fun freezeAndAnimateToCurrentState() = Unit
    }
}
+10 −4
Original line number Diff line number Diff line
@@ -25,11 +25,17 @@ import kotlinx.coroutines.flow.MutableStateFlow
class LockscreenSceneTransitionRepository @Inject constructor() {

    /**
     * This [KeyguardState] will indicate which sub state within KTF should be navigated to when the
     * next transition into the Lockscreen scene is started. It will be consumed exactly once and
     * after that the state will be set back to [DEFAULT_STATE].
     * This [KeyguardState] will indicate which sub-state within KTF should be navigated to next.
     *
     * This can be either starting a transition to the `Lockscreen` scene or cancelling a transition
     * from the `Lockscreen` scene and returning back to it.
     *
     * A `null` value means that no explicit target state was set and therefore the [DEFAULT_STATE]
     * should be used.
     *
     * Once consumed, this state should be reset to `null`.
     */
    val nextLockscreenTargetState: MutableStateFlow<KeyguardState> = MutableStateFlow(DEFAULT_STATE)
    val nextLockscreenTargetState: MutableStateFlow<KeyguardState?> = MutableStateFlow(null)

    companion object {
        val DEFAULT_STATE = KeyguardState.LOCKSCREEN
Loading