Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +57 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.shadeTestUtil import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -2135,6 +2136,14 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) fun glanceableHubToOccluded_communalKtfRefactor() = testScope.runTest { // GIVEN device is not dreaming powerInteractor.setAwakeForTest() keyguardRepository.setDreaming(false) keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) advanceTimeBy(600.milliseconds) // GIVEN a prior transition has run to GLANCEABLE_HUB communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") runCurrent() Loading Loading @@ -2298,6 +2307,54 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest coroutineContext.cancelChildren() } @Test @BrokenWithSceneContainer(339465026) @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) fun glanceableHubToOccludedDoesNotTriggerWhenDreamStateChanges_communalKtfRefactor() = testScope.runTest { // GIVEN that we are dreaming and not dozing powerInteractor.setAwakeForTest() keyguardRepository.setDreaming(true) keyguardRepository.setKeyguardOccluded(true) keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) advanceTimeBy(700.milliseconds) clearInvocations(transitionRepository) // GIVEN a prior transition has run to GLANCEABLE_HUB communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") runCurrent() assertThat(transitionRepository) .startedTransition( ownerName = CommunalSceneTransitionInteractor::class.simpleName, from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, ) clearInvocations(transitionRepository) // WHEN dream ends but we are still occluded keyguardRepository.setDreaming(false) runCurrent() assertThat(transitionRepository).noTransitionsStarted() // Simulate occlusion signal changing due to dream terminating and then occluding again // due to a new activity starting a couple milliseconds later. keyguardRepository.setKeyguardOccluded(false) advanceTimeBy(10.milliseconds) keyguardRepository.setKeyguardOccluded(true) advanceTimeBy(200.milliseconds) assertThat(transitionRepository) .startedTransition( ownerName = CommunalSceneTransitionInteractor::class.simpleName, from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, ) coroutineContext.cancelChildren() } private suspend fun TestScope.runTransitionAndSetWakefulness( from: KeyguardState, to: KeyguardState Loading packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt +23 −11 Original line number Diff line number Diff line Loading @@ -37,16 +37,21 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.noneOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @OptIn(FlowPreview::class) @SysUISingleton class FromGlanceableHubTransitionInteractor @Inject Loading Loading @@ -196,19 +201,26 @@ constructor( } } else if (communalSceneKtfRefactor()) { scope.launch { allOf( combine( keyguardInteractor.isKeyguardOccluded, noneOf( // Dream is a special-case of occluded, so filter out the dreaming // case here. keyguardInteractor.isDreaming, keyguardInteractor.isAbleToDream // Debounce the dreaming signal since there is a race condition between // the occluded and dreaming signals. We therefore add a small delay // to give enough time for occluded to flip to false when the dream // ends, to avoid transitioning to OCCLUDED erroneously when exiting // the dream. .debounce(100.milliseconds), ::Pair ) .sampleFilter( // When launching activities from widgets on the hub, we have a // custom occlusion animation. communalSceneInteractor.isLaunchingWidget, ), ) .filterRelevantKeyguardStateAnd { isOccludedAndNotDreamingNorLaunchingWidget -> isOccludedAndNotDreamingNorLaunchingWidget ) { launchingWidget -> !launchingWidget } .filterRelevantKeyguardStateAnd { (isOccluded, isDreaming) -> isOccluded && !isDreaming } .collect { _ -> communalSceneInteractor.changeScene( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +57 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.shadeTestUtil import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -2135,6 +2136,14 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) fun glanceableHubToOccluded_communalKtfRefactor() = testScope.runTest { // GIVEN device is not dreaming powerInteractor.setAwakeForTest() keyguardRepository.setDreaming(false) keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) advanceTimeBy(600.milliseconds) // GIVEN a prior transition has run to GLANCEABLE_HUB communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") runCurrent() Loading Loading @@ -2298,6 +2307,54 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest coroutineContext.cancelChildren() } @Test @BrokenWithSceneContainer(339465026) @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) fun glanceableHubToOccludedDoesNotTriggerWhenDreamStateChanges_communalKtfRefactor() = testScope.runTest { // GIVEN that we are dreaming and not dozing powerInteractor.setAwakeForTest() keyguardRepository.setDreaming(true) keyguardRepository.setKeyguardOccluded(true) keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) advanceTimeBy(700.milliseconds) clearInvocations(transitionRepository) // GIVEN a prior transition has run to GLANCEABLE_HUB communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") runCurrent() assertThat(transitionRepository) .startedTransition( ownerName = CommunalSceneTransitionInteractor::class.simpleName, from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, ) clearInvocations(transitionRepository) // WHEN dream ends but we are still occluded keyguardRepository.setDreaming(false) runCurrent() assertThat(transitionRepository).noTransitionsStarted() // Simulate occlusion signal changing due to dream terminating and then occluding again // due to a new activity starting a couple milliseconds later. keyguardRepository.setKeyguardOccluded(false) advanceTimeBy(10.milliseconds) keyguardRepository.setKeyguardOccluded(true) advanceTimeBy(200.milliseconds) assertThat(transitionRepository) .startedTransition( ownerName = CommunalSceneTransitionInteractor::class.simpleName, from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, ) coroutineContext.cancelChildren() } private suspend fun TestScope.runTransitionAndSetWakefulness( from: KeyguardState, to: KeyguardState Loading
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt +23 −11 Original line number Diff line number Diff line Loading @@ -37,16 +37,21 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.noneOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @OptIn(FlowPreview::class) @SysUISingleton class FromGlanceableHubTransitionInteractor @Inject Loading Loading @@ -196,19 +201,26 @@ constructor( } } else if (communalSceneKtfRefactor()) { scope.launch { allOf( combine( keyguardInteractor.isKeyguardOccluded, noneOf( // Dream is a special-case of occluded, so filter out the dreaming // case here. keyguardInteractor.isDreaming, keyguardInteractor.isAbleToDream // Debounce the dreaming signal since there is a race condition between // the occluded and dreaming signals. We therefore add a small delay // to give enough time for occluded to flip to false when the dream // ends, to avoid transitioning to OCCLUDED erroneously when exiting // the dream. .debounce(100.milliseconds), ::Pair ) .sampleFilter( // When launching activities from widgets on the hub, we have a // custom occlusion animation. communalSceneInteractor.isLaunchingWidget, ), ) .filterRelevantKeyguardStateAnd { isOccludedAndNotDreamingNorLaunchingWidget -> isOccludedAndNotDreamingNorLaunchingWidget ) { launchingWidget -> !launchingWidget } .filterRelevantKeyguardStateAnd { (isOccluded, isDreaming) -> isOccluded && !isDreaming } .collect { _ -> communalSceneInteractor.changeScene( Loading