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

Commit a9a31b38 authored by Lucas Silva's avatar Lucas Silva
Browse files

Fix transitions when communal ktf refactor enabled

This change removes the state syncing done by CommunalSceneStartable, in
favor of a more undirectional flow where KTF is determined by STL.

It also includes various fixes to ensure proper transitions when going
to edit mode, activity launches, and dismissing the hub when
unlocking.

Bug: 327225415
Flag: com.android.systemui.communal_scene_ktf_refactor
Test: atest CommunalSceneStartableTest
Test: atest KeyguardTransitionScenariosTest
Test: atest CommunalSceneTransitionInteractorTest
Change-Id: I51cd9410723ee2ff7eaab28730f9beb051626501
parent 810b79b5
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -16,11 +16,13 @@


package com.android.systemui.communal
package com.android.systemui.communal


import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
@@ -103,6 +105,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
    }
    }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun keyguardGoesAway_whenLaunchingWidget_doNotForceBlankScene() =
    fun keyguardGoesAway_whenLaunchingWidget_doNotForceBlankScene() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -123,6 +126,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun keyguardGoesAway_whenNotLaunchingWidget_forceBlankScene() =
    fun keyguardGoesAway_whenNotLaunchingWidget_forceBlankScene() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -143,6 +147,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun keyguardGoesAway_whenInEditMode_doesNotChangeScene() =
    fun keyguardGoesAway_whenInEditMode_doesNotChangeScene() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -180,6 +185,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun occluded_forceBlankScene() =
    fun occluded_forceBlankScene() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -199,6 +205,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun occluded_doesNotForceBlankSceneIfLaunchingActivityOverLockscreen() =
    fun occluded_doesNotForceBlankSceneIfLaunchingActivityOverLockscreen() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -218,6 +225,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun deviceDocked_doesNotForceCommunalIfTransitioningFromCommunal() =
    fun deviceDocked_doesNotForceCommunalIfTransitioningFromCommunal() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -235,6 +243,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun deviceAsleep_forceBlankSceneAfterTimeout() =
    fun deviceAsleep_forceBlankSceneAfterTimeout() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -256,6 +265,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun deviceAsleep_wakesUpBeforeTimeout_noChangeInScene() =
    fun deviceAsleep_wakesUpBeforeTimeout_noChangeInScene() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
@@ -483,6 +493,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    @DisableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    fun transitionFromDozingToGlanceableHub_forcesCommunal() =
    fun transitionFromDozingToGlanceableHub_forcesCommunal() =
        with(kosmos) {
        with(kosmos) {
            testScope.runTest {
            testScope.runTest {
+108 −1
Original line number Original line Diff line number Diff line
@@ -34,8 +34,11 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.realKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.realKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionInfo
@@ -46,6 +49,8 @@ import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.testKosmos
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,6 +58,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Before
@@ -211,8 +217,15 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
    @Test
    @Test
    fun transition_from_hub_end_in_dream() =
    fun transition_from_hub_end_in_dream() =
        testScope.runTest {
        testScope.runTest {
            // Device is dreaming and not dozing.
            kosmos.powerInteractor.setAwakeForTest()
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
            )
            kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
            kosmos.fakeKeyguardRepository.setDreaming(true)
            kosmos.fakeKeyguardRepository.setDreaming(true)
            runCurrent()
            kosmos.fakeKeyguardRepository.setDreamingWithOverlay(true)
            advanceTimeBy(100L)


            sceneTransitions.value = hubToBlank
            sceneTransitions.value = hubToBlank


@@ -254,6 +267,100 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
                )
                )
        }
        }


    /** Transition from hub to occluded. */
    @Test
    fun transition_from_hub_end_in_occluded() =
        testScope.runTest {
            kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
            runCurrent()

            sceneTransitions.value = hubToBlank

            val currentStep by collectLastValue(keyguardTransitionRepository.transitions)

            assertThat(currentStep)
                .isEqualTo(
                    TransitionStep(
                        from = GLANCEABLE_HUB,
                        to = OCCLUDED,
                        transitionState = STARTED,
                        value = 0f,
                        ownerName = ownerName,
                    )
                )

            progress.emit(0.4f)
            assertThat(currentStep)
                .isEqualTo(
                    TransitionStep(
                        from = GLANCEABLE_HUB,
                        to = OCCLUDED,
                        transitionState = RUNNING,
                        value = 0.4f,
                        ownerName = ownerName,
                    )
                )

            sceneTransitions.value = Idle(CommunalScenes.Blank)
            assertThat(currentStep)
                .isEqualTo(
                    TransitionStep(
                        from = GLANCEABLE_HUB,
                        to = OCCLUDED,
                        transitionState = FINISHED,
                        value = 1f,
                        ownerName = ownerName,
                    )
                )
        }

    /** Transition from hub to gone. */
    @Test
    fun transition_from_hub_end_in_gone() =
        testScope.runTest {
            kosmos.fakeKeyguardRepository.setKeyguardGoingAway(true)
            runCurrent()

            sceneTransitions.value = hubToBlank

            val currentStep by collectLastValue(keyguardTransitionRepository.transitions)

            assertThat(currentStep)
                .isEqualTo(
                    TransitionStep(
                        from = GLANCEABLE_HUB,
                        to = GONE,
                        transitionState = STARTED,
                        value = 0f,
                        ownerName = ownerName,
                    )
                )

            progress.emit(0.4f)
            assertThat(currentStep)
                .isEqualTo(
                    TransitionStep(
                        from = GLANCEABLE_HUB,
                        to = GONE,
                        transitionState = RUNNING,
                        value = 0.4f,
                        ownerName = ownerName,
                    )
                )

            sceneTransitions.value = Idle(CommunalScenes.Blank)
            assertThat(currentStep)
                .isEqualTo(
                    TransitionStep(
                        from = GLANCEABLE_HUB,
                        to = GONE,
                        transitionState = FINISHED,
                        value = 1f,
                        ownerName = ownerName,
                    )
                )
        }

    /** Transition from blank to hub, then settle back in blank. */
    /** Transition from blank to hub, then settle back in blank. */
    @Test
    @Test
    fun transition_from_blank_end_in_blank() =
    fun transition_from_blank_end_in_blank() =
+3 −1
Original line number Original line Diff line number Diff line
@@ -2230,11 +2230,13 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
    fun glanceableHubToDreaming_communalKtfRefactor() =
    fun glanceableHubToDreaming_communalKtfRefactor() =
        testScope.runTest {
        testScope.runTest {
            // GIVEN that we are dreaming and not dozing
            // GIVEN that we are dreaming and not dozing
            powerInteractor.setAwakeForTest()
            keyguardRepository.setDreaming(true)
            keyguardRepository.setDreaming(true)
            keyguardRepository.setDreamingWithOverlay(true)
            keyguardRepository.setDozeTransitionModel(
            keyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
            )
            )
            runCurrent()
            advanceTimeBy(100L)


            // GIVEN a prior transition has run to GLANCEABLE_HUB
            // GIVEN a prior transition has run to GLANCEABLE_HUB
            communalSceneInteractor.changeScene(CommunalScenes.Communal)
            communalSceneInteractor.changeScene(CommunalScenes.Communal)
+16 −13
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.provider.Settings
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.CoreStartable
import com.android.systemui.CoreStartable
import com.android.systemui.Flags.communalSceneKtfRefactor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
@@ -96,6 +97,7 @@ constructor(
            return
            return
        }
        }


        if (!communalSceneKtfRefactor()) {
            // Handle automatically switching based on keyguard state.
            // Handle automatically switching based on keyguard state.
            keyguardTransitionInteractor.startedKeyguardTransitionStep
            keyguardTransitionInteractor.startedKeyguardTransitionStep
                .mapLatest(::determineSceneAfterTransition)
                .mapLatest(::determineSceneAfterTransition)
@@ -103,13 +105,14 @@ constructor(
                .onEach { (nextScene, nextTransition) ->
                .onEach { (nextScene, nextTransition) ->
                    if (!communalSceneInteractor.isLaunchingWidget.value) {
                    if (!communalSceneInteractor.isLaunchingWidget.value) {
                        // When launching a widget, we don't want to animate the scene change or the
                        // When launching a widget, we don't want to animate the scene change or the
                    // Communal Hub will reveal the wallpaper even though it shouldn't. Instead we
                        // Communal Hub will reveal the wallpaper even though it shouldn't. Instead
                    // snap to the new scene as part of the launch animation, once the activity
                        // we snap to the new scene as part of the launch animation, once the
                    // launch is done, so we don't change scene here.
                        // activity launch is done, so we don't change scene here.
                        communalSceneInteractor.changeScene(nextScene, nextTransition)
                        communalSceneInteractor.changeScene(nextScene, nextTransition)
                    }
                    }
                }
                }
                .launchIn(applicationScope)
                .launchIn(applicationScope)
        }


        // TODO(b/322787129): re-enable once custom animations are in place
        // TODO(b/322787129): re-enable once custom animations are in place
        // Handle automatically switching to communal when docked.
        // Handle automatically switching to communal when docked.
+5 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import javax.inject.Inject
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -184,6 +185,10 @@ constructor(
                initialValue = false,
                initialValue = false,
            )
            )


    /** This flow will be true when idle on the hub and not transitioning to edit mode. */
    val isIdleOnCommunalNotEditMode: Flow<Boolean> =
        allOf(isIdleOnCommunal, editModeState.map { it == null })

    /**
    /**
     * Flow that emits a boolean if any portion of the communal UI is visible at all.
     * Flow that emits a boolean if any portion of the communal UI is visible at all.
     *
     *
Loading