diff options
11 files changed, 162 insertions, 6 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 ae615dde1e39..b32d9d6d4c93 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 @@ -26,14 +26,18 @@ import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState 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.domain.interactor.bouncerInteractor import com.android.systemui.bouncer.shared.logging.BouncerUiEvent 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.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor @@ -44,6 +48,7 @@ import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepo import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeTrustRepository +import com.android.systemui.keyguard.dismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope @@ -486,6 +491,11 @@ class SceneContainerStartableTest : SysuiTestCase() { QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING != 0L ) .isFalse() + assertThat( + sysUiState.flags and + QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED != 0L + ) + .isFalse() kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(false) runCurrent() @@ -499,6 +509,11 @@ class SceneContainerStartableTest : SysuiTestCase() { QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING != 0L ) .isTrue() + assertThat( + sysUiState.flags and + QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED != 0L + ) + .isTrue() } @Test @@ -1447,6 +1462,47 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentScene).isEqualTo(Scenes.Gone) } + @Test + fun notifyKeyguardDismissCallbacks_whenUnlocking_onDismissSucceeded() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + prepareState() + underTest.start() + 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.fakeExecutor.runAllReady() + + verify(dismissCallback).onDismissSucceeded() + } + + @Test + fun notifyKeyguardDismissCallbacks_whenLeavingBouncer_onDismissCancelled() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + prepareState() + underTest.start() + val dismissCallback: IKeyguardDismissCallback = mock() + kosmos.dismissCallbackRegistry.addCallback(dismissCallback) + + // Switch to bouncer: + sceneInteractor.changeScene(Scenes.Bouncer, "") + assertThat(currentScene).isEqualTo(Scenes.Bouncer) + + // Return to lockscreen: + sceneInteractor.changeScene(Scenes.Lockscreen, "") + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + runCurrent() + kosmos.fakeExecutor.runAllReady() + + verify(dismissCallback).onDismissCancelled() + } + private fun TestScope.emulateSceneTransition( transitionStateFlow: MutableStateFlow<ObservableTransitionState>, toScene: SceneKey, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index f06e04b70809..e73cae257c37 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -40,9 +40,11 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.util.mockito.mock @@ -105,6 +107,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest { kosmos.shadeInteractor }, { kosmos.deviceUnlockedInteractor }, { kosmos.sceneInteractor }, + { kosmos.sceneContainerOcclusionInteractor }, { kosmos.keyguardClockInteractor }, ) { override fun createDarkAnimator(): ObjectAnimator { @@ -336,6 +339,47 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } @Test + @EnableSceneContainer + fun start_hydratesStatusBarState_whileOccluded() = + testScope.runTest { + var statusBarState = underTest.state + val listener = + object : StatusBarStateController.StateListener { + override fun onStateChanged(newState: Int) { + statusBarState = newState + } + } + underTest.addCallback(listener) + + val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + val isOccluded by + collectLastValue(kosmos.sceneContainerOcclusionInteractor.invisibleDueToOcclusion) + kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( + showWhenLockedActivityOnTop = true, + taskInfo = mock(), + ) + runCurrent() + assertThat(isOccluded).isTrue() + + // Call start to begin hydrating based on the scene framework: + underTest.start() + + kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.Shade) + assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) + + kosmos.sceneInteractor.changeScene( + toScene = Scenes.QuickSettings, + loggingReason = "reason" + ) + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.QuickSettings) + assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) + } + + @Test fun leaveOpenOnKeyguard_whenGone_isFalse() = testScope.runTest { underTest.start() diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt index c8e896dacfb8..5084944685b6 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt +++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt @@ -84,9 +84,13 @@ constructor( SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it.scene != Scenes.Gone }, SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to { - it.scene == Scenes.Lockscreen || - it.scene == Scenes.NotificationsShade || - it.scene == Scenes.Shade + when { + it.invisibleDueToOcclusion -> false + it.scene == Scenes.Lockscreen -> true + it.scene == Scenes.NotificationsShade -> true + it.scene == Scenes.Shade -> true + else -> false + } }, SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt index 6bcd92316106..233e9b5bf818 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt @@ -121,7 +121,7 @@ constructor( private val SceneKey.canBeOccluded: Boolean get() = when (this) { - Scenes.Bouncer -> true + Scenes.Bouncer -> false Scenes.Communal -> true Scenes.Gone -> true Scenes.Lockscreen -> true 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 fbc074801855..84f7c37ac2e2 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 @@ -38,6 +38,7 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInt 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.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor @@ -126,6 +127,7 @@ constructor( private val shadeSessionStorage: SessionStorage, private val windowMgrLockscreenVisInteractor: WindowManagerLockscreenVisibilityInteractor, private val keyguardEnabledInteractor: KeyguardEnabledInteractor, + private val dismissCallbackRegistry: DismissCallbackRegistry, ) : CoreStartable { private val centralSurfaces: CentralSurfaces? get() = centralSurfacesOptLazy.get().getOrNull() @@ -144,6 +146,7 @@ constructor( hydrateBackStack() resetShadeSessions() handleKeyguardEnabledness() + notifyKeyguardDismissCallbacks() } else { sceneLogger.logFrameworkEnabled( isEnabled = false, @@ -713,4 +716,16 @@ constructor( } } } + + private fun notifyKeyguardDismissCallbacks() { + applicationScope.launch { + sceneInteractor.currentScene.pairwise().collect { (from, to) -> + when { + from != Scenes.Bouncer -> Unit + to == Scenes.Gone -> dismissCallbackRegistry.notifyDismissSucceeded() + else -> dismissCallbackRegistry.notifyDismissCancelled() + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 79218ae4ca20..89b7ccf09013 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -53,6 +53,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.res.R; +import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.model.Scenes; @@ -114,6 +115,7 @@ public class StatusBarStateControllerImpl implements private final Lazy<ShadeInteractor> mShadeInteractorLazy; private final Lazy<DeviceUnlockedInteractor> mDeviceUnlockedInteractorLazy; private final Lazy<SceneInteractor> mSceneInteractorLazy; + private final Lazy<SceneContainerOcclusionInteractor> mSceneContainerOcclusionInteractorLazy; private final Lazy<KeyguardClockInteractor> mKeyguardClockInteractorLazy; private int mState; private int mLastState; @@ -182,6 +184,7 @@ public class StatusBarStateControllerImpl implements Lazy<ShadeInteractor> shadeInteractorLazy, Lazy<DeviceUnlockedInteractor> deviceUnlockedInteractorLazy, Lazy<SceneInteractor> sceneInteractorLazy, + Lazy<SceneContainerOcclusionInteractor> sceneContainerOcclusionInteractor, Lazy<KeyguardClockInteractor> keyguardClockInteractorLazy) { mUiEventLogger = uiEventLogger; mInteractionJankMonitorLazy = interactionJankMonitorLazy; @@ -190,6 +193,7 @@ public class StatusBarStateControllerImpl implements mShadeInteractorLazy = shadeInteractorLazy; mDeviceUnlockedInteractorLazy = deviceUnlockedInteractorLazy; mSceneInteractorLazy = sceneInteractorLazy; + mSceneContainerOcclusionInteractorLazy = sceneContainerOcclusionInteractor; mKeyguardClockInteractorLazy = keyguardClockInteractorLazy; for (int i = 0; i < HISTORY_SIZE; i++) { mHistoricalRecords[i] = new HistoricalState(); @@ -214,6 +218,7 @@ public class StatusBarStateControllerImpl implements combineFlows( mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(), mSceneInteractorLazy.get().getCurrentScene(), + mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(), this::calculateStateFromSceneFramework), this::onStatusBarStateChanged); } @@ -664,10 +669,11 @@ public class StatusBarStateControllerImpl implements private int calculateStateFromSceneFramework( DeviceUnlockStatus deviceUnlockStatus, - SceneKey currentScene) { + SceneKey currentScene, + boolean isOccluded) { SceneContainerFlag.isUnexpectedlyInLegacyMode(); - if (deviceUnlockStatus.isUnlocked()) { + if (deviceUnlockStatus.isUnlocked() || isOccluded) { return StatusBarState.SHADE; } else { return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 88b832d15342..15c4bfce0a04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -464,6 +464,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { () -> mShadeInteractor, () -> mKosmos.getDeviceUnlockedInteractor(), () -> mKosmos.getSceneInteractor(), + () -> mKosmos.getSceneContainerOcclusionInteractor(), () -> mKosmos.getKeyguardClockInteractor()); KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext); @@ -621,6 +622,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { () -> mShadeInteractor, () -> mKosmos.getDeviceUnlockedInteractor(), () -> mKosmos.getSceneInteractor(), + () -> mKosmos.getSceneContainerOcclusionInteractor(), () -> mKosmos.getKeyguardClockInteractor()), mKeyguardBypassController, mDozeParameters, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/DismissCallbackRegistryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/DismissCallbackRegistryKosmos.kt new file mode 100644 index 000000000000..b12f947ab7fe --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/DismissCallbackRegistryKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard + +import com.android.systemui.concurrency.fakeExecutor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.dismissCallbackRegistry by Fixture { DismissCallbackRegistry(fakeExecutor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 31cdbc73f6fa..10ff73179f71 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -50,6 +50,7 @@ import com.android.systemui.model.sceneContainerPlugin import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.power.data.repository.fakePowerRepository import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.scrimStartable import com.android.systemui.scene.sceneContainerConfig @@ -142,4 +143,5 @@ class KosmosJavaAdapter() { val ongoingActivityChipsViewModel by lazy { kosmos.ongoingActivityChipsViewModel } val scrimController by lazy { kosmos.scrimController } val scrimStartable by lazy { kosmos.scrimStartable } + val sceneContainerOcclusionInteractor by lazy { kosmos.sceneContainerOcclusionInteractor } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt index ec56327c1101..f9f8d232611e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt @@ -22,6 +22,7 @@ import com.android.systemui.jank.interactionJankMonitor import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.StatusBarStateControllerImpl @@ -38,6 +39,7 @@ var Kosmos.statusBarStateController: SysuiStatusBarStateController by { shadeInteractor }, { deviceUnlockedInteractor }, { sceneInteractor }, + { sceneContainerOcclusionInteractor }, { keyguardClockInteractor }, ) } 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 a661ab648840..97fd2c43bb23 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 @@ -25,6 +25,7 @@ import com.android.systemui.classifier.falsingManager import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor +import com.android.systemui.keyguard.dismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor @@ -73,5 +74,6 @@ val Kosmos.sceneContainerStartable by Fixture { shadeSessionStorage = shadeSessionStorage, windowMgrLockscreenVisInteractor = windowManagerLockscreenVisibilityInteractor, keyguardEnabledInteractor = keyguardEnabledInteractor, + dismissCallbackRegistry = dismissCallbackRegistry, ) } |