Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +100 −32 Original line number Diff line number Diff line Loading @@ -54,7 +54,6 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.falsingCollector import com.android.systemui.classifier.falsingManager import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryBypassRepository import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor Loading Loading @@ -135,8 +134,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading Loading @@ -560,9 +557,74 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade() = fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade_singleShade() = kosmos.runTest { enableSingleShade() switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade( switchToQs = { sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") ObservableTransitionState.Idle(currentScene = Scenes.QuickSettings) }, expectedSceneWhileBouncerIsShowing = Scenes.QuickSettings, expectedLastBackStackSceneWhileBouncerIsShowing = Scenes.Lockscreen, expectedSceneAfterUnlock = Scenes.QuickSettings, expectedOverlaysAfterUnlock = emptySet(), expectedLastBackStackSceneAfterUnlock = Scenes.Gone, ) } @Test fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade_dualShade() = kosmos.runTest { enableDualShade() switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade( switchToQs = { sceneInteractor.showOverlay( Overlays.QuickSettingsShade, "switching to qs for test", ) ObservableTransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.QuickSettingsShade), ) }, expectedSceneWhileBouncerIsShowing = Scenes.Lockscreen, expectedLastBackStackSceneWhileBouncerIsShowing = null, expectedSceneAfterUnlock = Scenes.Gone, expectedOverlaysAfterUnlock = setOf(Overlays.QuickSettingsShade), expectedLastBackStackSceneAfterUnlock = null, ) } /** * Runs through the scenario where the bouncer is accessed while QS is being shown and the * device gets unlocked. This is a helper that can help multiple scenarios. * * @param switchToQs A function that switches to the QS scene or overlay and returns the `Idle` * representation of the expected current scene and overlays * @param expectedSceneWhileBouncerIsShowing The expected scene while the bouncer is showing. * The helper function will check that the current _scene_ is this while the bouncer is * showing * @param expectedLastBackStackSceneWhileBouncerIsShowing The expected last back stack scene * while the bouncer is showing. The helper function will check that this is the last scene on * the back stack while the bouncer is showing * @param expectedSceneAfterUnlock The expected scene once the device is unlocked. The helper * function will check that this is the current _scene_ once the device is unlocked * @param expectedOverlaysAfterUnlock The expected overlays once the device is unlocked. The * helper function will check that these are the current _overlays_ once the device is * unlocked * @param expectedLastBackStackSceneAfterUnlock The expected last back stack scene after the * device is unlocked. The helper function will check that this is the last scene on the back * stack once the device is unlocked */ private fun Kosmos.switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade( switchToQs: Kosmos.() -> ObservableTransitionState.Idle, expectedSceneWhileBouncerIsShowing: SceneKey, expectedLastBackStackSceneWhileBouncerIsShowing: SceneKey?, expectedSceneAfterUnlock: SceneKey, expectedOverlaysAfterUnlock: Set<OverlayKey>, expectedLastBackStackSceneAfterUnlock: SceneKey?, ) { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) val backStack by collectLastValue(sceneBackInteractor.backStack) Loading @@ -578,22 +640,28 @@ class SceneContainerStartableTest : SysuiTestCase() { underTest.start() runCurrent() sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings) val idleOnQs = switchToQs() transitionState.value = idleOnQs runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) assertThat(currentSceneKey).isEqualTo(idleOnQs.currentScene) assertThat(currentOverlays).isEqualTo(idleOnQs.currentOverlays) sceneInteractor.showOverlay(Overlays.Bouncer, "showing bouncer for test") transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings, setOf(Overlays.Bouncer)) ObservableTransitionState.Idle( expectedSceneWhileBouncerIsShowing, setOf(Overlays.Bouncer), ) runCurrent() assertThat(currentOverlays).contains(Overlays.Bouncer) assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Lockscreen) assertThat(backStack?.asIterable()?.lastOrNull()) .isEqualTo(expectedLastBackStackSceneWhileBouncerIsShowing) updateFingerprintAuthStatus(isSuccess = true) assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) assertThat(currentOverlays).doesNotContain(Overlays.Bouncer) assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Gone) assertThat(currentSceneKey).isEqualTo(expectedSceneAfterUnlock) assertThat(currentOverlays).isEqualTo(expectedOverlaysAfterUnlock) assertThat(backStack?.asIterable()?.lastOrNull()) .isEqualTo(expectedLastBackStackSceneAfterUnlock) } @Test Loading packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +106 −37 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInte import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor import com.android.systemui.deviceentry.shared.model.DeviceUnlockSource import com.android.systemui.kairos.internal.util.fastForEach import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor Loading Loading @@ -442,8 +443,8 @@ constructor( initialValue = null, ) deviceUnlockedInteractor.deviceUnlockStatus .mapNotNull { deviceUnlockStatus -> val (renderedScenes: List<SceneKey>, renderedOverlays) = .map { deviceUnlockStatus -> val (renderedScenes: List<SceneKey>, renderedOverlays: Set<OverlayKey>) = when (val transitionState = sceneInteractor.transitionState.value) { is ObservableTransitionState.Idle -> listOf(transitionState.currentScene) to Loading @@ -454,31 +455,34 @@ constructor( is ObservableTransitionState.Transition.OverlayTransition -> listOf(transitionState.currentScene) to setOfNotNull( transitionState.toContent.takeIf { it is OverlayKey }, transitionState.fromContent.takeIf { it is OverlayKey }, transitionState.toContent as? OverlayKey, transitionState.fromContent as? OverlayKey, ) } val isOnLockscreen = renderedScenes.contains(Scenes.Lockscreen) val isAlternateBouncerVisible = alternateBouncerInteractor.isVisibleState() val isOnPrimaryBouncer = Overlays.Bouncer in renderedOverlays if (!deviceUnlockStatus.isUnlocked) { return@mapNotNull if ( return@map if ( renderedScenes.any { it in keyguardScenes } || Overlays.Bouncer in renderedOverlays ) { // Already on a keyguard scene or bouncer, no need to change scenes. null SwitchSceneCommand.NoOp } else { // The device locked while on a scene that's not a keyguard scene, go // to Lockscreen. Scenes.Lockscreen to "device locked in a non-keyguard scene" SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Lockscreen, loggingReason = "device locked in a non-keyguard scene", ) } } if (powerInteractor.detailedWakefulness.value.isAsleep()) { // The logic below is for when the device becomes unlocked. That must be a // no-op if the device is not awake. return@mapNotNull null return@map SwitchSceneCommand.NoOp } if ( Loading @@ -487,6 +491,7 @@ constructor( ) { uiEventLogger.log(BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS) } val leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() when { isAlternateBouncerVisible -> { // When the device becomes unlocked when the alternate bouncer is Loading @@ -494,16 +499,16 @@ constructor( alternateBouncerInteractor.hide() // ... and go to Gone or stay on the current scene if ( isOnLockscreen || !statusBarStateController.leaveOpenOnKeyguardHide() ) { Scenes.Gone to "device was unlocked with alternate bouncer showing" + " and shade didn't need to be left open" if (isOnLockscreen || !leaveShadeOpen) { SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Gone, loggingReason = "device was unlocked while alternate bouncer" + " was showing and shade didn't need to be left open", ) } else { sceneBackInteractor.replaceLockscreenSceneOnBackStack() null SwitchSceneCommand.NoOp } } isOnPrimaryBouncer -> { Loading @@ -511,20 +516,40 @@ constructor( // Gone or remain in the current scene. If transition is a scene change, // take the destination scene. val targetScene = renderedScenes.last() if ( targetScene == Scenes.Lockscreen || !statusBarStateController.leaveOpenOnKeyguardHide() ) { Scenes.Gone to "device was unlocked with bouncer showing and shade" + " didn't need to be left open" if (targetScene == Scenes.Lockscreen || !leaveShadeOpen) { val loggingReason = buildString { append( "device was unlocked while the primary bouncer was showing" ) if (leaveShadeOpen) { append(" and shade needed to be left open") } else { append(" and shade didn't need to be left open") } } SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Gone, hideOverlays = if (leaveShadeOpen) { // Only hide the bouncer overlay, leaving any other // overlay (right now the only other overlays are // shades) visible. HideOverlayCommand.HideSome(Overlays.Bouncer) } else { HideOverlayCommand.HideAll }, loggingReason = loggingReason, ) } else { if (previousScene.value != Scenes.Gone) { sceneBackInteractor.replaceLockscreenSceneOnBackStack() } targetScene to "device was unlocked with primary bouncer showing," + " from sceneKey=$targetScene" SwitchSceneCommand.SwitchToScene( targetSceneKey = targetScene, loggingReason = "device was unlocked with primary bouncer" + " showing, from sceneKey=${targetScene.debugName}", ) } } isOnLockscreen -> Loading @@ -539,23 +564,36 @@ constructor( when { deviceUnlockStatus.deviceUnlockSource?.dismissesLockscreen == true -> Scenes.Gone to "device has been unlocked on lockscreen with bypass " + "enabled or using an active authentication " + "mechanism: ${deviceUnlockStatus.deviceUnlockSource}" else -> null SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Gone, loggingReason = "device was unlocked while lockscreen" + " with bypass enabled or using an active" + " authentication mechanism:" + " ${deviceUnlockStatus.deviceUnlockSource}", ) else -> SwitchSceneCommand.NoOp } // Not on lockscreen or bouncer, so remain in the current scene but since // unlocked, replace the Lockscreen scene from the bottom of the navigation // back stack with the Gone scene. else -> { sceneBackInteractor.replaceLockscreenSceneOnBackStack() null SwitchSceneCommand.NoOp } } } .collect { command: SwitchSceneCommand -> when (command) { is SwitchSceneCommand.SwitchToScene -> { switchToScene( targetSceneKey = command.targetSceneKey, hideOverlays = command.hideOverlays, loggingReason = command.loggingReason, ) } is SwitchSceneCommand.NoOp -> Unit } .collect { (targetSceneKey, loggingReason) -> switchToScene(targetSceneKey = targetSceneKey, loggingReason = loggingReason) } } } Loading Loading @@ -645,7 +683,12 @@ constructor( switchToScene( targetSceneKey = SceneFamilies.Home, loggingReason = "dream stopped", hideAllOverlays = deviceUnlockedInteractor.isUnlocked, hideOverlays = if (deviceUnlockedInteractor.isUnlocked) { HideOverlayCommand.HideAll } else { HideOverlayCommand.HideNone }, ) } } Loading Loading @@ -1004,14 +1047,20 @@ constructor( loggingReason: String, sceneState: Any? = null, freezeAndAnimateToCurrentState: Boolean = false, hideAllOverlays: Boolean = true, hideOverlays: HideOverlayCommand = HideOverlayCommand.HideAll, ) { if (hideOverlays is HideOverlayCommand.HideSome) { hideOverlays.overlays.fastForEach { overlay -> sceneInteractor.hideOverlay(overlay, loggingReason) } } sceneInteractor.changeScene( toScene = targetSceneKey, loggingReason = loggingReason, sceneState = sceneState, forceSettleToTargetScene = freezeAndAnimateToCurrentState, hideAllOverlays = hideAllOverlays, hideAllOverlays = hideOverlays == HideOverlayCommand.HideAll, ) } Loading Loading @@ -1104,6 +1153,26 @@ constructor( } } sealed interface SwitchSceneCommand { data object NoOp : SwitchSceneCommand data class SwitchToScene( val targetSceneKey: SceneKey, val loggingReason: String, val hideOverlays: HideOverlayCommand = HideOverlayCommand.HideAll, ) : SwitchSceneCommand } sealed interface HideOverlayCommand { data object HideAll : HideOverlayCommand data object HideNone : HideOverlayCommand class HideSome(val overlays: List<OverlayKey>) : HideOverlayCommand { constructor(overlay: OverlayKey) : this(listOf(overlay)) } } companion object { private const val TAG = "SceneContainerStartable" } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +100 −32 Original line number Diff line number Diff line Loading @@ -54,7 +54,6 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.falsingCollector import com.android.systemui.classifier.falsingManager import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryBypassRepository import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor Loading Loading @@ -135,8 +134,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading Loading @@ -560,9 +557,74 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade() = fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade_singleShade() = kosmos.runTest { enableSingleShade() switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade( switchToQs = { sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") ObservableTransitionState.Idle(currentScene = Scenes.QuickSettings) }, expectedSceneWhileBouncerIsShowing = Scenes.QuickSettings, expectedLastBackStackSceneWhileBouncerIsShowing = Scenes.Lockscreen, expectedSceneAfterUnlock = Scenes.QuickSettings, expectedOverlaysAfterUnlock = emptySet(), expectedLastBackStackSceneAfterUnlock = Scenes.Gone, ) } @Test fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade_dualShade() = kosmos.runTest { enableDualShade() switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade( switchToQs = { sceneInteractor.showOverlay( Overlays.QuickSettingsShade, "switching to qs for test", ) ObservableTransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.QuickSettingsShade), ) }, expectedSceneWhileBouncerIsShowing = Scenes.Lockscreen, expectedLastBackStackSceneWhileBouncerIsShowing = null, expectedSceneAfterUnlock = Scenes.Gone, expectedOverlaysAfterUnlock = setOf(Overlays.QuickSettingsShade), expectedLastBackStackSceneAfterUnlock = null, ) } /** * Runs through the scenario where the bouncer is accessed while QS is being shown and the * device gets unlocked. This is a helper that can help multiple scenarios. * * @param switchToQs A function that switches to the QS scene or overlay and returns the `Idle` * representation of the expected current scene and overlays * @param expectedSceneWhileBouncerIsShowing The expected scene while the bouncer is showing. * The helper function will check that the current _scene_ is this while the bouncer is * showing * @param expectedLastBackStackSceneWhileBouncerIsShowing The expected last back stack scene * while the bouncer is showing. The helper function will check that this is the last scene on * the back stack while the bouncer is showing * @param expectedSceneAfterUnlock The expected scene once the device is unlocked. The helper * function will check that this is the current _scene_ once the device is unlocked * @param expectedOverlaysAfterUnlock The expected overlays once the device is unlocked. The * helper function will check that these are the current _overlays_ once the device is * unlocked * @param expectedLastBackStackSceneAfterUnlock The expected last back stack scene after the * device is unlocked. The helper function will check that this is the last scene on the back * stack once the device is unlocked */ private fun Kosmos.switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade( switchToQs: Kosmos.() -> ObservableTransitionState.Idle, expectedSceneWhileBouncerIsShowing: SceneKey, expectedLastBackStackSceneWhileBouncerIsShowing: SceneKey?, expectedSceneAfterUnlock: SceneKey, expectedOverlaysAfterUnlock: Set<OverlayKey>, expectedLastBackStackSceneAfterUnlock: SceneKey?, ) { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) val backStack by collectLastValue(sceneBackInteractor.backStack) Loading @@ -578,22 +640,28 @@ class SceneContainerStartableTest : SysuiTestCase() { underTest.start() runCurrent() sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings) val idleOnQs = switchToQs() transitionState.value = idleOnQs runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) assertThat(currentSceneKey).isEqualTo(idleOnQs.currentScene) assertThat(currentOverlays).isEqualTo(idleOnQs.currentOverlays) sceneInteractor.showOverlay(Overlays.Bouncer, "showing bouncer for test") transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings, setOf(Overlays.Bouncer)) ObservableTransitionState.Idle( expectedSceneWhileBouncerIsShowing, setOf(Overlays.Bouncer), ) runCurrent() assertThat(currentOverlays).contains(Overlays.Bouncer) assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Lockscreen) assertThat(backStack?.asIterable()?.lastOrNull()) .isEqualTo(expectedLastBackStackSceneWhileBouncerIsShowing) updateFingerprintAuthStatus(isSuccess = true) assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) assertThat(currentOverlays).doesNotContain(Overlays.Bouncer) assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Gone) assertThat(currentSceneKey).isEqualTo(expectedSceneAfterUnlock) assertThat(currentOverlays).isEqualTo(expectedOverlaysAfterUnlock) assertThat(backStack?.asIterable()?.lastOrNull()) .isEqualTo(expectedLastBackStackSceneAfterUnlock) } @Test Loading
packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +106 −37 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInte import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor import com.android.systemui.deviceentry.shared.model.DeviceUnlockSource import com.android.systemui.kairos.internal.util.fastForEach import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor Loading Loading @@ -442,8 +443,8 @@ constructor( initialValue = null, ) deviceUnlockedInteractor.deviceUnlockStatus .mapNotNull { deviceUnlockStatus -> val (renderedScenes: List<SceneKey>, renderedOverlays) = .map { deviceUnlockStatus -> val (renderedScenes: List<SceneKey>, renderedOverlays: Set<OverlayKey>) = when (val transitionState = sceneInteractor.transitionState.value) { is ObservableTransitionState.Idle -> listOf(transitionState.currentScene) to Loading @@ -454,31 +455,34 @@ constructor( is ObservableTransitionState.Transition.OverlayTransition -> listOf(transitionState.currentScene) to setOfNotNull( transitionState.toContent.takeIf { it is OverlayKey }, transitionState.fromContent.takeIf { it is OverlayKey }, transitionState.toContent as? OverlayKey, transitionState.fromContent as? OverlayKey, ) } val isOnLockscreen = renderedScenes.contains(Scenes.Lockscreen) val isAlternateBouncerVisible = alternateBouncerInteractor.isVisibleState() val isOnPrimaryBouncer = Overlays.Bouncer in renderedOverlays if (!deviceUnlockStatus.isUnlocked) { return@mapNotNull if ( return@map if ( renderedScenes.any { it in keyguardScenes } || Overlays.Bouncer in renderedOverlays ) { // Already on a keyguard scene or bouncer, no need to change scenes. null SwitchSceneCommand.NoOp } else { // The device locked while on a scene that's not a keyguard scene, go // to Lockscreen. Scenes.Lockscreen to "device locked in a non-keyguard scene" SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Lockscreen, loggingReason = "device locked in a non-keyguard scene", ) } } if (powerInteractor.detailedWakefulness.value.isAsleep()) { // The logic below is for when the device becomes unlocked. That must be a // no-op if the device is not awake. return@mapNotNull null return@map SwitchSceneCommand.NoOp } if ( Loading @@ -487,6 +491,7 @@ constructor( ) { uiEventLogger.log(BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS) } val leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() when { isAlternateBouncerVisible -> { // When the device becomes unlocked when the alternate bouncer is Loading @@ -494,16 +499,16 @@ constructor( alternateBouncerInteractor.hide() // ... and go to Gone or stay on the current scene if ( isOnLockscreen || !statusBarStateController.leaveOpenOnKeyguardHide() ) { Scenes.Gone to "device was unlocked with alternate bouncer showing" + " and shade didn't need to be left open" if (isOnLockscreen || !leaveShadeOpen) { SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Gone, loggingReason = "device was unlocked while alternate bouncer" + " was showing and shade didn't need to be left open", ) } else { sceneBackInteractor.replaceLockscreenSceneOnBackStack() null SwitchSceneCommand.NoOp } } isOnPrimaryBouncer -> { Loading @@ -511,20 +516,40 @@ constructor( // Gone or remain in the current scene. If transition is a scene change, // take the destination scene. val targetScene = renderedScenes.last() if ( targetScene == Scenes.Lockscreen || !statusBarStateController.leaveOpenOnKeyguardHide() ) { Scenes.Gone to "device was unlocked with bouncer showing and shade" + " didn't need to be left open" if (targetScene == Scenes.Lockscreen || !leaveShadeOpen) { val loggingReason = buildString { append( "device was unlocked while the primary bouncer was showing" ) if (leaveShadeOpen) { append(" and shade needed to be left open") } else { append(" and shade didn't need to be left open") } } SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Gone, hideOverlays = if (leaveShadeOpen) { // Only hide the bouncer overlay, leaving any other // overlay (right now the only other overlays are // shades) visible. HideOverlayCommand.HideSome(Overlays.Bouncer) } else { HideOverlayCommand.HideAll }, loggingReason = loggingReason, ) } else { if (previousScene.value != Scenes.Gone) { sceneBackInteractor.replaceLockscreenSceneOnBackStack() } targetScene to "device was unlocked with primary bouncer showing," + " from sceneKey=$targetScene" SwitchSceneCommand.SwitchToScene( targetSceneKey = targetScene, loggingReason = "device was unlocked with primary bouncer" + " showing, from sceneKey=${targetScene.debugName}", ) } } isOnLockscreen -> Loading @@ -539,23 +564,36 @@ constructor( when { deviceUnlockStatus.deviceUnlockSource?.dismissesLockscreen == true -> Scenes.Gone to "device has been unlocked on lockscreen with bypass " + "enabled or using an active authentication " + "mechanism: ${deviceUnlockStatus.deviceUnlockSource}" else -> null SwitchSceneCommand.SwitchToScene( targetSceneKey = Scenes.Gone, loggingReason = "device was unlocked while lockscreen" + " with bypass enabled or using an active" + " authentication mechanism:" + " ${deviceUnlockStatus.deviceUnlockSource}", ) else -> SwitchSceneCommand.NoOp } // Not on lockscreen or bouncer, so remain in the current scene but since // unlocked, replace the Lockscreen scene from the bottom of the navigation // back stack with the Gone scene. else -> { sceneBackInteractor.replaceLockscreenSceneOnBackStack() null SwitchSceneCommand.NoOp } } } .collect { command: SwitchSceneCommand -> when (command) { is SwitchSceneCommand.SwitchToScene -> { switchToScene( targetSceneKey = command.targetSceneKey, hideOverlays = command.hideOverlays, loggingReason = command.loggingReason, ) } is SwitchSceneCommand.NoOp -> Unit } .collect { (targetSceneKey, loggingReason) -> switchToScene(targetSceneKey = targetSceneKey, loggingReason = loggingReason) } } } Loading Loading @@ -645,7 +683,12 @@ constructor( switchToScene( targetSceneKey = SceneFamilies.Home, loggingReason = "dream stopped", hideAllOverlays = deviceUnlockedInteractor.isUnlocked, hideOverlays = if (deviceUnlockedInteractor.isUnlocked) { HideOverlayCommand.HideAll } else { HideOverlayCommand.HideNone }, ) } } Loading Loading @@ -1004,14 +1047,20 @@ constructor( loggingReason: String, sceneState: Any? = null, freezeAndAnimateToCurrentState: Boolean = false, hideAllOverlays: Boolean = true, hideOverlays: HideOverlayCommand = HideOverlayCommand.HideAll, ) { if (hideOverlays is HideOverlayCommand.HideSome) { hideOverlays.overlays.fastForEach { overlay -> sceneInteractor.hideOverlay(overlay, loggingReason) } } sceneInteractor.changeScene( toScene = targetSceneKey, loggingReason = loggingReason, sceneState = sceneState, forceSettleToTargetScene = freezeAndAnimateToCurrentState, hideAllOverlays = hideAllOverlays, hideAllOverlays = hideOverlays == HideOverlayCommand.HideAll, ) } Loading Loading @@ -1104,6 +1153,26 @@ constructor( } } sealed interface SwitchSceneCommand { data object NoOp : SwitchSceneCommand data class SwitchToScene( val targetSceneKey: SceneKey, val loggingReason: String, val hideOverlays: HideOverlayCommand = HideOverlayCommand.HideAll, ) : SwitchSceneCommand } sealed interface HideOverlayCommand { data object HideAll : HideOverlayCommand data object HideNone : HideOverlayCommand class HideSome(val overlays: List<OverlayKey>) : HideOverlayCommand { constructor(overlay: OverlayKey) : this(listOf(overlay)) } } companion object { private const val TAG = "SceneContainerStartable" } Loading