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

Commit 62bd697b authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[flexiglass] Expose the new snapToScene API.

ag/27208377 exposes a new snapToScene API in
MutableSceneTransitionLayoutState. This CL exposes that throughout the
Flexiglass scene framework APIs such that users of SceneInteractor can
now call snapToScene in the same way as they can already call
changeScene.

Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Bug: 330672236
Test: added unit tests for new functionality
Test: manually tested with follow up CL
Change-Id: I23def24c8fbb95048ea8c512d50cd9d177ecebd9
parent e4a75f90
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -62,4 +62,10 @@ class SceneTransitionLayoutDataSource(
            coroutineScope = coroutineScope,
        )
    }

    override fun snapToScene(toScene: SceneKey) {
        state.snapToScene(
            scene = toScene,
        )
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -70,6 +70,9 @@ class SceneContainerRepositoryTest : SysuiTestCase() {

            underTest.changeScene(Scenes.Shade)
            assertThat(currentScene).isEqualTo(Scenes.Shade)

            underTest.snapToScene(Scenes.QuickSettings)
            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
        }

    @Test(expected = IllegalStateException::class)
@@ -79,6 +82,13 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
        underTest.changeScene(Scenes.Shade)
    }

    @Test(expected = IllegalStateException::class)
    fun snapToScene_noSuchSceneInContainer_throws() {
        kosmos.sceneKeys = listOf(Scenes.QuickSettings, Scenes.Lockscreen)
        val underTest = kosmos.sceneContainerRepository
        underTest.snapToScene(Scenes.Shade)
    }

    @Test
    fun isVisible() =
        testScope.runTest {
+65 −0
Original line number Diff line number Diff line
@@ -125,6 +125,71 @@ class SceneInteractorTest : SysuiTestCase() {
            underTest.changeScene(Scenes.Gone, "reason")
        }

    @Test
    fun snapToScene_toUnknownScene_doesNothing() =
        testScope.runTest {
            val sceneKeys =
                listOf(
                    Scenes.QuickSettings,
                    Scenes.Shade,
                    Scenes.Lockscreen,
                    Scenes.Gone,
                    Scenes.Communal,
                )
            val navigationDistances =
                mapOf(
                    Scenes.Gone to 0,
                    Scenes.Lockscreen to 0,
                    Scenes.Communal to 1,
                    Scenes.Shade to 2,
                    Scenes.QuickSettings to 3,
                )
            kosmos.sceneContainerConfig =
                SceneContainerConfig(sceneKeys, Scenes.Lockscreen, navigationDistances)
            underTest = kosmos.sceneInteractor
            val currentScene by collectLastValue(underTest.currentScene)
            val previousScene = currentScene
            assertThat(previousScene).isNotEqualTo(Scenes.Bouncer)
            underTest.snapToScene(Scenes.Bouncer, "reason")
            assertThat(currentScene).isEqualTo(previousScene)
        }

    @Test
    fun snapToScene() =
        testScope.runTest {
            underTest = kosmos.sceneInteractor

            val currentScene by collectLastValue(underTest.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

            underTest.snapToScene(Scenes.Shade, "reason")
            assertThat(currentScene).isEqualTo(Scenes.Shade)
        }

    @Test
    fun snapToScene_toGoneWhenUnl_doesNotThrow() =
        testScope.runTest {
            underTest = kosmos.sceneInteractor

            val currentScene by collectLastValue(underTest.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            runCurrent()

            underTest.snapToScene(Scenes.Gone, "reason")
            assertThat(currentScene).isEqualTo(Scenes.Gone)
        }

    @Test(expected = IllegalStateException::class)
    fun snapToScene_toGoneWhenStillLocked_throws() =
        testScope.runTest {
            underTest = kosmos.sceneInteractor
            underTest.snapToScene(Scenes.Gone, "reason")
        }

    @Test
    fun sceneChanged_inDataSource() =
        testScope.runTest {
+8 −0
Original line number Diff line number Diff line
@@ -87,6 +87,14 @@ constructor(
        )
    }

    fun snapToScene(
        toScene: SceneKey,
    ) {
        dataSource.snapToScene(
            toScene = toScene,
        )
    }

    /** Sets whether the container is visible. */
    fun setVisible(isVisible: Boolean) {
        _isVisible.value = isVisible
+64 −9
Original line number Diff line number Diff line
@@ -162,19 +162,45 @@ constructor(
        loggingReason: String,
        transitionKey: TransitionKey? = null,
    ) {
        if (!repository.allSceneKeys().contains(toScene)) {
        val currentSceneKey = currentScene.value
        if (
            !validateSceneChange(
                from = currentSceneKey,
                to = toScene,
                loggingReason = loggingReason,
            )
        ) {
            return
        }

        check(
            toScene != Scenes.Gone || deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked
        ) {
            "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
                " change was: $loggingReason"
        logger.logSceneChangeRequested(
            from = currentSceneKey,
            to = toScene,
            reason = loggingReason,
            isInstant = false,
        )

        repository.changeScene(toScene, transitionKey)
    }

    /**
     * Requests a scene change to the given scene.
     *
     * The change is instantaneous and not animated; it will be observable in the next frame and
     * there will be no transition animation.
     */
    fun snapToScene(
        toScene: SceneKey,
        loggingReason: String,
    ) {
        val currentSceneKey = currentScene.value
        if (currentSceneKey == toScene) {
        if (
            !validateSceneChange(
                from = currentSceneKey,
                to = toScene,
                loggingReason = loggingReason,
            )
        ) {
            return
        }

@@ -182,9 +208,10 @@ constructor(
            from = currentSceneKey,
            to = toScene,
            reason = loggingReason,
            isInstant = true,
        )

        repository.changeScene(toScene, transitionKey)
        repository.snapToScene(toScene)
    }

    /**
@@ -249,4 +276,32 @@ constructor(
    ): Boolean {
        return raw || isRemoteUserInteractionOngoing
    }

    /**
     * Validates that the given scene change is allowed.
     *
     * Will throw a runtime exception for illegal states (for example, attempting to change to a
     * scene that's not part of the current scene framework configuration).
     *
     * @param from The current scene being transitioned away from
     * @param to The desired destination scene to transition to
     * @param loggingReason The reason why the transition is requested, for logging purposes
     * @return `true` if the scene change is valid; `false` if it shouldn't happen
     */
    private fun validateSceneChange(
        from: SceneKey,
        to: SceneKey,
        loggingReason: String,
    ): Boolean {
        if (!repository.allSceneKeys().contains(to)) {
            return false
        }

        check(to != Scenes.Gone || deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked) {
            "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
                " change was: $loggingReason"
        }

        return from != to
    }
}
Loading