Loading packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +5 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope Loading Loading @@ -71,9 +72,7 @@ constructor( } @Composable override fun SceneScope.Content( modifier: Modifier, ) = override fun SceneScope.Content(modifier: Modifier) = BouncerScene( viewModel = rememberViewModel("BouncerScene") { contentViewModelFactory.create() }, dialogFactory = dialogFactory, Loading @@ -89,6 +88,8 @@ private fun SceneScope.BouncerScene( ) { val backgroundColor = MaterialTheme.colorScheme.surface DisposableEffect(Unit) { onDispose { viewModel.onUiDestroyed() } } Box(modifier) { Canvas(Modifier.element(Bouncer.Elements.Background).fillMaxSize()) { drawRect(color = backgroundColor) Loading @@ -101,7 +102,7 @@ private fun SceneScope.BouncerScene( dialogFactory, Modifier.element(Bouncer.Elements.Content) .sysuiResTag(Bouncer.TestTags.Root) .fillMaxSize() .fillMaxSize(), ) } } packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModelTest.kt +24 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,11 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic 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.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.res.R Loading Loading @@ -212,6 +217,25 @@ class BouncerSceneContentViewModelTest : SysuiTestCase() { assertThat(isFoldSplitRequired).isTrue() } @Test fun onUiDestroyed_clearsPendingDismissAction() = kosmos.runTest { val dismissAction by collectLastValue(fakeKeyguardRepository.dismissAction) fakeKeyguardRepository.setDismissAction( DismissAction.RunImmediately( onDismissAction = { KeyguardDone.IMMEDIATE }, onCancelAction = {}, message = "", willAnimateOnLockscreen = true, ) ) assertThat(dismissAction).isNotEqualTo(DismissAction.None) underTest.onUiDestroyed() assertThat(dismissAction).isEqualTo(DismissAction.None) } private fun authMethodsToTest(): List<AuthenticationMethodModel> { return listOf(None, Pin, Password, Pattern, Sim) } Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt +21 −56 Original line number Diff line number Diff line Loading @@ -35,10 +35,9 @@ 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.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.power.data.repository.fakePowerRepository 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 Loading Loading @@ -221,28 +220,6 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None) } @Test fun resetDismissAction() = testScope.runTest { kosmos.setSceneTransition(Idle(Scenes.Bouncer)) var wasOnCancelInvoked = false startInteractor() keyguardRepository.setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = {}, onCancelAction = { wasOnCancelInvoked = true }, message = "message", willAnimateOnLockscreen = true, ) ) assertThat(wasOnCancelInvoked).isFalse() kosmos.setSceneTransition(Idle(Scenes.Lockscreen)) runCurrent() assertThat(wasOnCancelInvoked).isTrue() assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None) } @Test fun doNotResetDismissActionOnUnlockedShade() = testScope.runTest { Loading Loading @@ -271,37 +248,6 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { assertThat(keyguardRepository.dismissAction.value).isEqualTo(dismissAction) } @Test fun resetDismissAction_onBouncer_OnAsleep() = testScope.runTest { kosmos.setSceneTransition(Idle(Scenes.Bouncer)) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None ) var wasOnCancelInvoked = false startInteractor() keyguardRepository.setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = {}, onCancelAction = { wasOnCancelInvoked = true }, message = "message", willAnimateOnLockscreen = true, ) ) assertThat(wasOnCancelInvoked).isFalse() kosmos.fakePowerRepository.updateWakefulness( rawState = WakefulnessState.ASLEEP, lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = WakeSleepReason.TIMEOUT, powerButtonLaunchGestureTriggered = false, ) runCurrent() assertThat(wasOnCancelInvoked).isTrue() assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None) } @Test fun setDismissAction_callsCancelRunnableOnPreviousDismissAction() = testScope.runTest { Loading Loading @@ -410,6 +356,25 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { assertThat(wasCancelActionInvoked).isFalse() } @Test fun clearDismissAction() = kosmos.runTest { val dismissAction by collectLastValue(fakeKeyguardRepository.dismissAction) fakeKeyguardRepository.setDismissAction( DismissAction.RunImmediately( onDismissAction = { KeyguardDone.IMMEDIATE }, onCancelAction = {}, message = "", willAnimateOnLockscreen = true, ) ) assertThat(dismissAction).isNotEqualTo(DismissAction.None) underTest.clearDismissAction() assertThat(dismissAction).isEqualTo(DismissAction.None) } private fun TestScope.startInteractor() { testScope.backgroundScope.launchTraced( "KeyguardDismissActionInteractorTest#startInteractor" Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +32 −1 Original line number Diff line number Diff line Loading @@ -190,6 +190,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor; @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback; @Mock private KeyguardDismissActionInteractor mKeyguardDismissActionInteractor; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); Loading Loading @@ -236,7 +238,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mKeyguardTransitionInteractor, mock(KeyguardDismissTransitionInteractor.class), StandardTestDispatcher(null, null), () -> mock(KeyguardDismissActionInteractor.class), () -> mKeyguardDismissActionInteractor, mSelectedUserInteractor, mock(JavaAdapter.class), () -> mSceneInteractor, Loading Loading @@ -968,4 +970,33 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { ); verify(mAlternateBouncerInteractor).hide(); } @Test public void hideAlternateBouncer_clearsDismissActionByDefault() { clearInvocations(mKeyguardDismissActionInteractor); mStatusBarKeyguardViewManager.hideAlternateBouncer(/* updateScrim= */ true); verify(mKeyguardDismissActionInteractor).clearDismissAction(); } @Test public void hideAlternateBouncer_clearsDismissActionExplicitly() { clearInvocations(mKeyguardDismissActionInteractor); mStatusBarKeyguardViewManager.hideAlternateBouncer( /* updateScrim= */ true, /* clearDismissAction= */ true); verify(mKeyguardDismissActionInteractor).clearDismissAction(); } @Test public void hideAlternateBouncer_doNotClearDismissActionExplicitly() { clearInvocations(mKeyguardDismissActionInteractor); mStatusBarKeyguardViewManager.hideAlternateBouncer( /* updateScrim= */ true, /* clearDismissAction= */ false); verify(mKeyguardDismissActionInteractor, never()).clearDismissAction(); } } packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +11 −0 Original line number Diff line number Diff line Loading @@ -174,9 +174,20 @@ public interface KeyguardViewController { /** * Stop showing the alternate bouncer, if showing. * * <p>Should be like calling {@link #hideAlternateBouncer(boolean, boolean)} with a {@code true} * {@code clearDismissAction} parameter. */ void hideAlternateBouncer(boolean updateScrim); /** * Stop showing the alternate bouncer, if showing. * * @param updateScrim Whether to update the scrim * @param clearDismissAction Whether the pending dismiss action should be cleared */ void hideAlternateBouncer(boolean updateScrim, boolean clearDismissAction); // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently // only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from // achieving complete abstraction away from where the Keyguard View is mounted. Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +5 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope Loading Loading @@ -71,9 +72,7 @@ constructor( } @Composable override fun SceneScope.Content( modifier: Modifier, ) = override fun SceneScope.Content(modifier: Modifier) = BouncerScene( viewModel = rememberViewModel("BouncerScene") { contentViewModelFactory.create() }, dialogFactory = dialogFactory, Loading @@ -89,6 +88,8 @@ private fun SceneScope.BouncerScene( ) { val backgroundColor = MaterialTheme.colorScheme.surface DisposableEffect(Unit) { onDispose { viewModel.onUiDestroyed() } } Box(modifier) { Canvas(Modifier.element(Bouncer.Elements.Background).fillMaxSize()) { drawRect(color = backgroundColor) Loading @@ -101,7 +102,7 @@ private fun SceneScope.BouncerScene( dialogFactory, Modifier.element(Bouncer.Elements.Content) .sysuiResTag(Bouncer.TestTags.Root) .fillMaxSize() .fillMaxSize(), ) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModelTest.kt +24 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,11 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic 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.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.res.R Loading Loading @@ -212,6 +217,25 @@ class BouncerSceneContentViewModelTest : SysuiTestCase() { assertThat(isFoldSplitRequired).isTrue() } @Test fun onUiDestroyed_clearsPendingDismissAction() = kosmos.runTest { val dismissAction by collectLastValue(fakeKeyguardRepository.dismissAction) fakeKeyguardRepository.setDismissAction( DismissAction.RunImmediately( onDismissAction = { KeyguardDone.IMMEDIATE }, onCancelAction = {}, message = "", willAnimateOnLockscreen = true, ) ) assertThat(dismissAction).isNotEqualTo(DismissAction.None) underTest.onUiDestroyed() assertThat(dismissAction).isEqualTo(DismissAction.None) } private fun authMethodsToTest(): List<AuthenticationMethodModel> { return listOf(None, Pin, Password, Pattern, Sim) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt +21 −56 Original line number Diff line number Diff line Loading @@ -35,10 +35,9 @@ 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.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.power.data.repository.fakePowerRepository 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 Loading Loading @@ -221,28 +220,6 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None) } @Test fun resetDismissAction() = testScope.runTest { kosmos.setSceneTransition(Idle(Scenes.Bouncer)) var wasOnCancelInvoked = false startInteractor() keyguardRepository.setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = {}, onCancelAction = { wasOnCancelInvoked = true }, message = "message", willAnimateOnLockscreen = true, ) ) assertThat(wasOnCancelInvoked).isFalse() kosmos.setSceneTransition(Idle(Scenes.Lockscreen)) runCurrent() assertThat(wasOnCancelInvoked).isTrue() assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None) } @Test fun doNotResetDismissActionOnUnlockedShade() = testScope.runTest { Loading Loading @@ -271,37 +248,6 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { assertThat(keyguardRepository.dismissAction.value).isEqualTo(dismissAction) } @Test fun resetDismissAction_onBouncer_OnAsleep() = testScope.runTest { kosmos.setSceneTransition(Idle(Scenes.Bouncer)) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None ) var wasOnCancelInvoked = false startInteractor() keyguardRepository.setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = {}, onCancelAction = { wasOnCancelInvoked = true }, message = "message", willAnimateOnLockscreen = true, ) ) assertThat(wasOnCancelInvoked).isFalse() kosmos.fakePowerRepository.updateWakefulness( rawState = WakefulnessState.ASLEEP, lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = WakeSleepReason.TIMEOUT, powerButtonLaunchGestureTriggered = false, ) runCurrent() assertThat(wasOnCancelInvoked).isTrue() assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None) } @Test fun setDismissAction_callsCancelRunnableOnPreviousDismissAction() = testScope.runTest { Loading Loading @@ -410,6 +356,25 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { assertThat(wasCancelActionInvoked).isFalse() } @Test fun clearDismissAction() = kosmos.runTest { val dismissAction by collectLastValue(fakeKeyguardRepository.dismissAction) fakeKeyguardRepository.setDismissAction( DismissAction.RunImmediately( onDismissAction = { KeyguardDone.IMMEDIATE }, onCancelAction = {}, message = "", willAnimateOnLockscreen = true, ) ) assertThat(dismissAction).isNotEqualTo(DismissAction.None) underTest.clearDismissAction() assertThat(dismissAction).isEqualTo(DismissAction.None) } private fun TestScope.startInteractor() { testScope.backgroundScope.launchTraced( "KeyguardDismissActionInteractorTest#startInteractor" Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +32 −1 Original line number Diff line number Diff line Loading @@ -190,6 +190,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor; @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback; @Mock private KeyguardDismissActionInteractor mKeyguardDismissActionInteractor; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); Loading Loading @@ -236,7 +238,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mKeyguardTransitionInteractor, mock(KeyguardDismissTransitionInteractor.class), StandardTestDispatcher(null, null), () -> mock(KeyguardDismissActionInteractor.class), () -> mKeyguardDismissActionInteractor, mSelectedUserInteractor, mock(JavaAdapter.class), () -> mSceneInteractor, Loading Loading @@ -968,4 +970,33 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { ); verify(mAlternateBouncerInteractor).hide(); } @Test public void hideAlternateBouncer_clearsDismissActionByDefault() { clearInvocations(mKeyguardDismissActionInteractor); mStatusBarKeyguardViewManager.hideAlternateBouncer(/* updateScrim= */ true); verify(mKeyguardDismissActionInteractor).clearDismissAction(); } @Test public void hideAlternateBouncer_clearsDismissActionExplicitly() { clearInvocations(mKeyguardDismissActionInteractor); mStatusBarKeyguardViewManager.hideAlternateBouncer( /* updateScrim= */ true, /* clearDismissAction= */ true); verify(mKeyguardDismissActionInteractor).clearDismissAction(); } @Test public void hideAlternateBouncer_doNotClearDismissActionExplicitly() { clearInvocations(mKeyguardDismissActionInteractor); mStatusBarKeyguardViewManager.hideAlternateBouncer( /* updateScrim= */ true, /* clearDismissAction= */ false); verify(mKeyguardDismissActionInteractor, never()).clearDismissAction(); } }
packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +11 −0 Original line number Diff line number Diff line Loading @@ -174,9 +174,20 @@ public interface KeyguardViewController { /** * Stop showing the alternate bouncer, if showing. * * <p>Should be like calling {@link #hideAlternateBouncer(boolean, boolean)} with a {@code true} * {@code clearDismissAction} parameter. */ void hideAlternateBouncer(boolean updateScrim); /** * Stop showing the alternate bouncer, if showing. * * @param updateScrim Whether to update the scrim * @param clearDismissAction Whether the pending dismiss action should be cleared */ void hideAlternateBouncer(boolean updateScrim, boolean clearDismissAction); // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently // only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from // achieving complete abstraction away from where the Keyguard View is mounted. Loading