diff options
| author | 2024-07-19 15:46:31 +0000 | |
|---|---|---|
| committer | 2024-07-22 20:01:38 +0000 | |
| commit | cab6bef41693fa9769badd472ed3c29e2c98a449 (patch) | |
| tree | bef020fac5be4c905d216647cab0cf7312b118fe | |
| parent | 0d4eb64ae4b1ba177cc971ff2bd07a533d8ad95c (diff) | |
[flexiglass] Handle dismiss actions from shade => primary bouncer => gone/shade
SceneContainerStartable:
Check whether leaveOpenOnDismissKeyguard is true to determine
whether to go to the GONE or SHADE scene. "Leave open" is referring
to leaving the shade open.
KeyguardDismissActionInteractor:
When the device becomes unlocked on the SHADE, run any pending
dismiss actions.
Test: setup pin/pattern/password; pull down the shade on the
lockscreen; tap on a notification; successfully authenticate;
observe device transitions to the notification intent
Test: setup pin/pattern/password; pull down the shade on the
lockscreen; tap on the "edit qs" affordance; successfully authenticate;
observe user is back on QS with the "edit QS" UI
Test: setup pin/pattern/password; longpress on a QS tile;
successfully authenticate; observe longpress action occurs
Test: atest SceneContainerStartableTest KeyguardDismissActionInteractorTest
Bug: 308819693
Flag: com.android.systemui.scene_container
Change-Id: Iefe6fae0167407013f406093dd773b1039a5f691
7 files changed, 118 insertions, 38 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index 540a85aeb695..f26c39d0ba6d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -78,6 +78,7 @@ import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.phone.centralSurfaces import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository +import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat @@ -274,9 +275,10 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked() = + fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) + kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open val transitionState = prepareState( @@ -306,6 +308,39 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test + fun switchFromBouncerToGoneWhenDeviceUnlocked_whenDoNotLeaveOpenShade() = + testScope.runTest { + val currentSceneKey by collectLastValue(sceneInteractor.currentScene) + kosmos.sysuiStatusBarStateController.leaveOpen = false // don't leave shade open + + val transitionState = + prepareState( + authenticationMethod = AuthenticationMethodModel.Pin, + isDeviceUnlocked = false, + initialSceneKey = Scenes.Lockscreen, + ) + assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) + underTest.start() + runCurrent() + + sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") + transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings) + runCurrent() + assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) + + sceneInteractor.changeScene(Scenes.Bouncer, "switching to bouncer for test") + transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer) + runCurrent() + assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer) + + kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( + SuccessFingerprintAuthenticationStatus(0, true) + ) + + assertThat(currentSceneKey).isEqualTo(Scenes.Gone) + } + + @Test fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt index f4d82659971d..1152d7040a38 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt @@ -19,12 +19,15 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.KeyguardDone import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter import com.android.systemui.util.kotlin.sample @@ -35,6 +38,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.map @@ -51,6 +55,8 @@ constructor( transitionInteractor: KeyguardTransitionInteractor, val dismissInteractor: KeyguardDismissInteractor, @Application private val applicationScope: CoroutineScope, + sceneInteractor: SceneInteractor, + deviceEntryInteractor: DeviceEntryInteractor, ) { val dismissAction: Flow<DismissAction> = repository.dismissAction @@ -80,9 +86,26 @@ constructor( .filter { it } .map {} + /** + * True if the any variation of the notification shade or quick settings is showing AND the + * device is unlocked. Else, false. + */ + private val isOnShadeWhileUnlocked: Flow<Boolean> = + combine( + sceneInteractor.currentScene, + deviceEntryInteractor.isUnlocked, + ) { scene, isUnlocked -> + isUnlocked && + (scene == Scenes.Shade || + scene == Scenes.NotificationsShade || + scene == Scenes.QuickSettings || + scene == Scenes.QuickSettingsShade) + } + .distinctUntilChanged() val executeDismissAction: Flow<() -> KeyguardDone> = merge( finishedTransitionToGone, + isOnShadeWhileUnlocked.filter { it }.map {}, dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction ) .sample(dismissAction) @@ -99,9 +122,10 @@ constructor( scene = Scenes.Bouncer, stateWithoutSceneContainer = PRIMARY_BOUNCER ), - transitionInteractor.isFinishedIn(state = ALTERNATE_BOUNCER) - ) { isOnGone, isOnBouncer, isOnAltBouncer -> - !isOnGone && !isOnBouncer && !isOnAltBouncer + transitionInteractor.isFinishedIn(state = ALTERNATE_BOUNCER), + isOnShadeWhileUnlocked, + ) { isOnGone, isOnBouncer, isOnAltBouncer, isOnShadeWhileUnlocked -> + !isOnGone && !isOnBouncer && !isOnAltBouncer && !isOnShadeWhileUnlocked } .filter { it } .sampleFilter(dismissAction) { it !is DismissAction.None } @@ -112,6 +136,7 @@ constructor( } fun runAfterKeyguardGone(runnable: Runnable) { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = { runnable.run() }, @@ -123,15 +148,18 @@ constructor( } fun setDismissAction(dismissAction: DismissAction) { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return repository.dismissAction.value.onCancelAction.run() repository.setDismissAction(dismissAction) } fun handleDismissAction() { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return repository.setDismissAction(DismissAction.None) } suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return dismissInteractor.setKeyguardDone(keyguardDoneTiming) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt index b29302721253..74a7262d7889 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt @@ -23,6 +23,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInte import com.android.systemui.log.core.LogLevel import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.sample +import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -34,7 +35,7 @@ import kotlinx.coroutines.launch class KeyguardDismissActionBinder @Inject constructor( - private val interactor: KeyguardDismissActionInteractor, + private val interactorLazy: Lazy<KeyguardDismissActionInteractor>, @Application private val scope: CoroutineScope, private val keyguardLogger: KeyguardLogger, ) : CoreStartable { @@ -44,6 +45,7 @@ constructor( return } + val interactor = interactorLazy.get() scope.launch { interactor.executeDismissAction.collect { log("executeDismissAction") diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 72f37fc98e17..3fca84efdd05 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -60,6 +60,7 @@ import com.android.systemui.scene.shared.logger.SceneLogger import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor @@ -130,6 +131,7 @@ constructor( private val windowMgrLockscreenVisInteractor: WindowManagerLockscreenVisibilityInteractor, private val keyguardEnabledInteractor: KeyguardEnabledInteractor, private val dismissCallbackRegistry: DismissCallbackRegistry, + private val statusBarStateController: SysuiStatusBarStateController, ) : CoreStartable { private val centralSurfaces: CentralSurfaces? get() = centralSurfacesOptLazy.get().getOrNull() @@ -356,8 +358,13 @@ constructor( isOnBouncer -> // When the device becomes unlocked in Bouncer, go to previous scene, // or Gone. - if (previousScene.value == Scenes.Lockscreen) { - Scenes.Gone to "device was unlocked in Bouncer scene" + if ( + previousScene.value == Scenes.Lockscreen || + !statusBarStateController.leaveOpenOnKeyguardHide() + ) { + Scenes.Gone to + "device was unlocked in Bouncer scene and shade" + + " didn't need to be left open" } else { val prevScene = previousScene.value (prevScene ?: Scenes.Gone) to diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt index 8bc0a6040e12..a310520763e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt @@ -20,21 +20,24 @@ package com.android.systemui.keyguard.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.KeyguardDone -import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.kosmos.testScope import com.android.systemui.scene.data.repository.Idle +import com.android.systemui.scene.data.repository.Transition import com.android.systemui.scene.data.repository.setSceneTransition +import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -44,13 +47,12 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest +@EnableSceneContainer @RunWith(AndroidJUnit4::class) class KeyguardDismissActionInteractorTest : SysuiTestCase() { val kosmos = testKosmos() private val keyguardRepository = kosmos.fakeKeyguardRepository - private val transitionRepository = kosmos.fakeKeyguardTransitionRepository - private val testScope = kosmos.testScope private lateinit var dismissInteractorWithDependencies: @@ -74,6 +76,8 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { transitionInteractor = kosmos.keyguardTransitionInteractor, dismissInteractor = dismissInteractorWithDependencies.interactor, applicationScope = testScope.backgroundScope, + sceneInteractor = kosmos.sceneInteractor, + deviceEntryInteractor = kosmos.deviceEntryInteractor, ) } @@ -158,7 +162,6 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { } @Test - @DisableSceneContainer fun executeDismissAction_dismissKeyguardRequestWithoutImmediateDismissAction() = testScope.runTest { val executeDismissAction by collectLastValue(underTest.executeDismissAction) @@ -175,43 +178,37 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { ) assertThat(executeDismissAction).isNull() - // WHEN the keyguard is GONE - transitionRepository.sendTransitionSteps( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.GONE, - testScope, - ) + kosmos.setSceneTransition(Idle(Scenes.Gone)) + assertThat(executeDismissAction).isNotNull() } @Test - @EnableSceneContainer - fun executeDismissAction_dismissKeyguardRequestWithoutImmediateDismissAction_scene_container() = + fun resetDismissAction() = testScope.runTest { - val executeDismissAction by collectLastValue(underTest.executeDismissAction) - - // WHEN a keyguard action will run after the keyguard is gone - val onDismissAction = {} + kosmos.setSceneTransition(Idle(Scenes.Bouncer)) + val resetDismissAction by collectLastValue(underTest.resetDismissAction) keyguardRepository.setDismissAction( DismissAction.RunAfterKeyguardGone( - dismissAction = onDismissAction, + dismissAction = {}, onCancelAction = {}, message = "message", willAnimateOnLockscreen = true, ) ) - assertThat(executeDismissAction).isNull() - - kosmos.setSceneTransition(Idle(Scenes.Gone)) - - assertThat(executeDismissAction).isNotNull() + assertThat(resetDismissAction).isNull() + kosmos.setSceneTransition(Idle(Scenes.Lockscreen)) + assertThat(resetDismissAction).isEqualTo(Unit) } @Test - fun resetDismissAction() = + fun doNotResetDismissActionOnUnlockedShade() = testScope.runTest { + kosmos.setSceneTransition(Idle(Scenes.Bouncer)) + kosmos.fakeAuthenticationRepository.setAuthenticationMethod( + AuthenticationMethodModel.None + ) val resetDismissAction by collectLastValue(underTest.resetDismissAction) - keyguardRepository.setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = {}, @@ -220,12 +217,16 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { willAnimateOnLockscreen = true, ) ) - transitionRepository.sendTransitionSteps( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.AOD, - testScope + assertThat(resetDismissAction).isNull() + + kosmos.setSceneTransition( + Transition( + from = Scenes.Bouncer, + to = Scenes.NotificationsShade, + progress = flowOf(1f), + ) ) - assertThat(resetDismissAction).isEqualTo(Unit) + assertThat(resetDismissAction).isNull() } @Test diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt index 2c6d44f10152..fe156e2037cf 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt @@ -16,9 +16,11 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.sceneInteractor import kotlinx.coroutines.ExperimentalCoroutinesApi @ExperimentalCoroutinesApi @@ -29,5 +31,7 @@ val Kosmos.keyguardDismissActionInteractor by transitionInteractor = keyguardTransitionInteractor, dismissInteractor = keyguardDismissInteractor, applicationScope = testScope.backgroundScope, + sceneInteractor = sceneInteractor, + deviceEntryInteractor = deviceEntryInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt index 03a42bc4178e..8e76a0bf5a13 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt @@ -34,6 +34,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testScope import com.android.systemui.model.sysUiState +import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor @@ -46,6 +47,7 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.heads import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.phone.centralSurfacesOptional import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor +import com.android.systemui.statusbar.sysuiStatusBarStateController val Kosmos.sceneContainerStartable by Fixture { SceneContainerStartable( @@ -77,5 +79,6 @@ val Kosmos.sceneContainerStartable by Fixture { windowMgrLockscreenVisInteractor = windowManagerLockscreenVisibilityInteractor, keyguardEnabledInteractor = keyguardEnabledInteractor, dismissCallbackRegistry = dismissCallbackRegistry, + statusBarStateController = sysuiStatusBarStateController, ) } |