summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Beverly <beverlyt@google.com> 2024-08-16 13:58:23 +0000
committer Beverly <beverlyt@google.com> 2024-08-19 18:45:15 +0000
commitddf249118d35308d0a137de4b018b99bc3c83b73 (patch)
treeaf83d8f6c63237f56fe3da52a0cd3fc7372e184b
parentb5508fff1f099fa155ced5170fec299ac55971d5 (diff)
[flexiglass] hide and cancel AlternateBouncer when device sleeps
After the device goes to sleep, the alternate bouncer should immediately hide and any dismiss actions should be reset and dismiss callbacks should receive an onDismissCancelled call. Previously, the dismiss registry callbacks would miss success and cancelled calls. This CL will call onDismissCancelled when the device goes to sleep from the alternate or primary bouncer and will call onDismissSucceeded when the device becomes unlocked. Fixes: 353955910 Flag: com.android.systemui.scene_container Test: atest SceneContainerStartableTest KeyguardDismissActionInteractorTest Test: look at DismissCallbackRegistry logs from logcat and observe the cancellation and success calls from the alt/primary bouncer on AlternateBouncer => sleeping, PrimaryBouncer => sleeping, AlternateBouncer => Primary Bouncer Test: Tap on a notification with an intent to bring up the alternate bouncer. Press the power button to put the device to sleep. Wake the device and use the FP sensor to authenticate. Observe that the device enters and does NOT open the stale notification intent. Change-Id: Ifd6c1a1a1c36da584eaa8a96e73a3848bf943244
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt33
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt4
6 files changed, 127 insertions, 26 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 2dfff3ffc72b..5533a8b90056 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
@@ -28,9 +28,7 @@ import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.uiEventLoggerFake
import com.android.internal.policy.IKeyguardDismissCallback
import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
-import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
@@ -331,6 +329,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
SuccessFingerprintAuthenticationStatus(0, true)
)
+ runCurrent()
assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings)
assertThat(alternateBouncerVisible).isFalse()
@@ -481,6 +480,33 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
@Test
+ fun hideAlternateBouncerAndNotifyDismissCancelledWhenDeviceSleeps() =
+ testScope.runTest {
+ val alternateBouncerVisible by
+ collectLastValue(bouncerRepository.alternateBouncerVisible)
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ prepareState(
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Shade,
+ )
+ assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
+ bouncerRepository.setAlternateVisible(true)
+ underTest.start()
+
+ // run all pending dismiss succeeded/cancelled calls from setup:
+ kosmos.fakeExecutor.runAllReady()
+
+ val dismissCallback: IKeyguardDismissCallback = mock()
+ kosmos.dismissCallbackRegistry.addCallback(dismissCallback)
+ powerInteractor.setAsleepForTest()
+ runCurrent()
+ kosmos.fakeExecutor.runAllReady()
+
+ assertThat(alternateBouncerVisible).isFalse()
+ verify(dismissCallback).onDismissCancelled()
+ }
+
+ @Test
fun switchToLockscreenWhenDeviceSleepsLocked() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -1618,19 +1644,27 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
@Test
- fun notifyKeyguardDismissCallbacks_whenUnlocking_onDismissSucceeded() =
+ fun notifyKeyguardDismissCallbacks_whenUnlockingFromBouncer_onDismissSucceeded() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- prepareState()
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ prepareState(
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ isDeviceUnlocked = false,
+ initialSceneKey = Scenes.Bouncer,
+ )
+ assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
underTest.start()
+
+ // run all pending dismiss succeeded/cancelled calls from setup:
+ kosmos.fakeExecutor.runAllReady()
+
val dismissCallback: IKeyguardDismissCallback = mock()
kosmos.dismissCallbackRegistry.addCallback(dismissCallback)
- // Switch to bouncer and unlock device:
- sceneInteractor.changeScene(Scenes.Bouncer, "")
- assertThat(currentScene).isEqualTo(Scenes.Bouncer)
- kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
- assertThat(currentScene).isEqualTo(Scenes.Gone)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
kosmos.fakeExecutor.runAllReady()
verify(dismissCallback).onDismissSucceeded()
@@ -1639,19 +1673,26 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun notifyKeyguardDismissCallbacks_whenLeavingBouncer_onDismissCancelled() =
testScope.runTest {
+ val isUnlocked by collectLastValue(kosmos.deviceEntryInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene)
prepareState()
underTest.start()
+
+ // run all pending dismiss succeeded/cancelled calls from setup:
+ kosmos.fakeExecutor.runAllReady()
+
val dismissCallback: IKeyguardDismissCallback = mock()
kosmos.dismissCallbackRegistry.addCallback(dismissCallback)
// Switch to bouncer:
sceneInteractor.changeScene(Scenes.Bouncer, "")
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
+ runCurrent()
- // Return to lockscreen:
+ // Return to lockscreen when isUnlocked=false:
sceneInteractor.changeScene(Scenes.Lockscreen, "")
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(isUnlocked).isFalse()
runCurrent()
kosmos.fakeExecutor.runAllReady()
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 1c445a703bc4..7801c00d83b8 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
@@ -17,15 +17,16 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
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.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolver
import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolver
@@ -61,6 +62,8 @@ constructor(
deviceEntryInteractor: DeviceEntryInteractor,
quickSettingsSceneFamilyResolver: QuickSettingsSceneFamilyResolver,
notifShadeSceneFamilyResolver: NotifShadeSceneFamilyResolver,
+ powerInteractor: PowerInteractor,
+ alternateBouncerInteractor: AlternateBouncerInteractor,
) {
val dismissAction: Flow<DismissAction> = repository.dismissAction
@@ -124,10 +127,12 @@ constructor(
scene = Scenes.Bouncer,
stateWithoutSceneContainer = PRIMARY_BOUNCER
),
- transitionInteractor.isFinishedIn(state = ALTERNATE_BOUNCER),
+ alternateBouncerInteractor.isVisible,
isOnShadeWhileUnlocked,
- ) { isOnGone, isOnBouncer, isOnAltBouncer, isOnShadeWhileUnlocked ->
- !isOnGone && !isOnBouncer && !isOnAltBouncer && !isOnShadeWhileUnlocked
+ powerInteractor.isAsleep,
+ ) { isOnGone, isOnBouncer, isOnAltBouncer, isOnShadeWhileUnlocked, isAsleep ->
+ (!isOnGone && !isOnBouncer && !isOnAltBouncer && !isOnShadeWhileUnlocked) ||
+ isAsleep
}
.filter { it }
.sampleFilter(dismissAction) { it !is DismissAction.None }
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 e73664d43952..cc46216b6e43 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
@@ -152,7 +152,7 @@ constructor(
hydrateBackStack()
resetShadeSessions()
handleKeyguardEnabledness()
- notifyKeyguardDismissCallbacks()
+ notifyKeyguardDismissCancelledCallbacks()
refreshLockscreenEnabled()
} else {
sceneLogger.logFrameworkEnabled(
@@ -379,8 +379,10 @@ constructor(
when {
isAlternateBouncerVisible -> {
// When the device becomes unlocked when the alternate bouncer is
- // showing, always hide the alternate bouncer...
+ // showing, always hide the alternate bouncer and notify dismiss
+ // succeeded
alternateBouncerInteractor.hide()
+ dismissCallbackRegistry.notifyDismissSucceeded()
// ... and go to Gone or stay on the current scene
if (
@@ -394,9 +396,11 @@ constructor(
null
}
}
- isOnPrimaryBouncer ->
+ isOnPrimaryBouncer -> {
// When the device becomes unlocked in primary Bouncer,
+ // notify dismiss succeeded and
// go to previous scene or Gone.
+ dismissCallbackRegistry.notifyDismissSucceeded()
if (
previousScene.value == Scenes.Lockscreen ||
!statusBarStateController.leaveOpenOnKeyguardHide()
@@ -410,6 +414,7 @@ constructor(
"device was unlocked with primary bouncer showing," +
" from sceneKey=$prevScene"
}
+ }
isOnLockscreen ->
// The lockscreen should be dismissed automatically in 2 scenarios:
// 1. When face auth bypass is enabled and authentication happens while
@@ -468,6 +473,9 @@ constructor(
applicationScope.launch {
powerInteractor.isAsleep.collect { isAsleep ->
if (isAsleep) {
+ alternateBouncerInteractor.hide()
+ dismissCallbackRegistry.notifyDismissCancelled()
+
switchToScene(
targetSceneKey = Scenes.Lockscreen,
loggingReason = "device is starting to sleep",
@@ -771,15 +779,23 @@ constructor(
}
}
- private fun notifyKeyguardDismissCallbacks() {
+ private fun notifyKeyguardDismissCancelledCallbacks() {
applicationScope.launch {
- sceneInteractor.currentScene.pairwise().collect { (from, to) ->
- when {
- from != Scenes.Bouncer -> Unit
- to == Scenes.Gone -> dismissCallbackRegistry.notifyDismissSucceeded()
- else -> dismissCallbackRegistry.notifyDismissCancelled()
+ combine(
+ deviceEntryInteractor.isUnlocked,
+ sceneInteractor.currentScene.pairwise(),
+ ) { isUnlocked, (from, to) ->
+ when {
+ from != Scenes.Bouncer -> false
+ to != Scenes.Gone && !isUnlocked -> true
+ else -> false
+ }
+ }
+ .collect { notifyKeyguardDismissCancelled ->
+ if (notifyKeyguardDismissCancelled) {
+ dismissCallbackRegistry.notifyDismissCancelled()
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index de4d14d31da3..0f93ff2b70ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -545,6 +545,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@VisibleForTesting
void consumeFromAlternateBouncerTransitionSteps(TransitionStep step) {
+ SceneContainerFlag.assertInLegacyMode();
hideAlternateBouncer(false);
}
@@ -554,6 +555,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
*/
@VisibleForTesting
void consumeKeyguardAuthenticatedBiometricsHandled(Unit handled) {
+ SceneContainerFlag.assertInLegacyMode();
if (mAlternateBouncerInteractor.isVisibleState()) {
hideAlternateBouncer(false);
}
@@ -981,7 +983,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
} else {
showBouncerOrKeyguard(hideBouncerWhenShowing, isFalsingReset);
}
- if (hideBouncerWhenShowing) {
+ if (!SceneContainerFlag.isEnabled() && hideBouncerWhenShowing) {
hideAlternateBouncer(true);
}
mKeyguardUpdateManager.sendKeyguardReset();
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 32d059b2f037..a0fe538bdd2b 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
@@ -22,6 +22,7 @@ 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.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.EnableSceneContainer
@@ -29,6 +30,10 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.KeyguardDone
import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.fakePowerRepository
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.setSceneTransition
@@ -82,6 +87,8 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() {
deviceEntryInteractor = kosmos.deviceEntryInteractor,
quickSettingsSceneFamilyResolver = kosmos.quickSettingsSceneFamilyResolver,
notifShadeSceneFamilyResolver = kosmos.notifShadeSceneFamilyResolver,
+ powerInteractor = kosmos.powerInteractor,
+ alternateBouncerInteractor = kosmos.alternateBouncerInteractor,
)
}
@@ -234,6 +241,32 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() {
}
@Test
+ fun resetDismissAction_onBouncer_OnAsleep() =
+ testScope.runTest {
+ kosmos.setSceneTransition(Idle(Scenes.Bouncer))
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.None
+ )
+ val resetDismissAction by collectLastValue(underTest.resetDismissAction)
+ keyguardRepository.setDismissAction(
+ DismissAction.RunAfterKeyguardGone(
+ dismissAction = {},
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ assertThat(resetDismissAction).isNull()
+ kosmos.fakePowerRepository.updateWakefulness(
+ rawState = WakefulnessState.ASLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.TIMEOUT,
+ powerButtonLaunchGestureTriggered = false,
+ )
+ assertThat(resetDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
fun setDismissAction_callsCancelRunnableOnPreviousDismissAction() =
testScope.runTest {
val dismissAction by collectLastValue(underTest.dismissAction)
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 957f092c188a..27eadb147055 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,10 +16,12 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
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.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
@@ -37,5 +39,7 @@ val Kosmos.keyguardDismissActionInteractor by
deviceEntryInteractor = deviceEntryInteractor,
quickSettingsSceneFamilyResolver = quickSettingsSceneFamilyResolver,
notifShadeSceneFamilyResolver = notifShadeSceneFamilyResolver,
+ powerInteractor = powerInteractor,
+ alternateBouncerInteractor = alternateBouncerInteractor,
)
}