Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { authenticationInteractor = dagger.Lazy { kosmos.authenticationInteractor }, windowController = mock(), deviceProvisioningInteractor = kosmos.deviceProvisioningInteractor, centralSurfaces = mock(), ) startable.start() Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +226 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.startable import android.app.StatusBarManager import android.os.PowerManager import android.platform.test.annotations.EnableFlags import android.view.Display Loading Loading @@ -48,6 +49,7 @@ import com.android.systemui.scene.shared.model.ObservableTransitionState import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel 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.policy.domain.interactor.deviceProvisioningInteractor Loading @@ -65,6 +67,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never Loading @@ -78,6 +81,7 @@ import org.mockito.MockitoAnnotations class SceneContainerStartableTest : SysuiTestCase() { @Mock private lateinit var windowController: NotificationShadeWindowController @Mock private lateinit var centralSurfaces: CentralSurfaces private val kosmos = testKosmos() private val testScope = kosmos.testScope Loading Loading @@ -115,6 +119,7 @@ class SceneContainerStartableTest : SysuiTestCase() { authenticationInteractor = dagger.Lazy { authenticationInteractor }, windowController = windowController, deviceProvisioningInteractor = kosmos.deviceProvisioningInteractor, centralSurfaces = centralSurfaces, ) } Loading Loading @@ -763,6 +768,227 @@ class SceneContainerStartableTest : SysuiTestCase() { verify(windowController, times(2)).setNotificationShadeFocusable(false) } @Test fun hydrateInteractionState_whileLocked() = testScope.runTest { val transitionStateFlow = prepareState( initialSceneKey = SceneKey.Lockscreen, ) underTest.start() runCurrent() verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Bouncer, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, false, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, true, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Shade, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, false, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, true, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.QuickSettings, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) } @Test fun hydrateInteractionState_whileUnlocked() = testScope.runTest { val transitionStateFlow = prepareState( isDeviceUnlocked = true, initialSceneKey = SceneKey.Gone, ) underTest.start() verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Bouncer, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Shade, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.QuickSettings, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) } private fun TestScope.emulateSceneTransition( transitionStateFlow: MutableStateFlow<ObservableTransitionState>, toScene: SceneKey, verifyBeforeTransition: (() -> Unit)? = null, verifyDuringTransition: (() -> Unit)? = null, verifyAfterTransition: (() -> Unit)? = null, ) { val fromScene = sceneInteractor.desiredScene.value.key sceneInteractor.changeScene(SceneModel(toScene), "reason") runCurrent() verifyBeforeTransition?.invoke() transitionStateFlow.value = ObservableTransitionState.Transition( fromScene = fromScene, toScene = toScene, progress = flowOf(0.5f), isInitiatedByUserInput = true, isUserInputOngoing = flowOf(true), ) runCurrent() verifyDuringTransition?.invoke() transitionStateFlow.value = ObservableTransitionState.Idle( scene = toScene, ) runCurrent() verifyAfterTransition?.invoke() } private fun TestScope.prepareState( isDeviceUnlocked: Boolean = false, isBypassEnabled: Boolean = false, Loading packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +44 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.startable import android.app.StatusBarManager import com.android.systemui.CoreStartable import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel Loading @@ -42,6 +43,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor import com.android.systemui.util.asIndenting import com.android.systemui.util.printSection Loading Loading @@ -85,6 +87,7 @@ constructor( private val authenticationInteractor: Lazy<AuthenticationInteractor>, private val windowController: NotificationShadeWindowController, private val deviceProvisioningInteractor: DeviceProvisioningInteractor, private val centralSurfaces: CentralSurfaces, ) : CoreStartable { override fun start() { Loading @@ -95,6 +98,7 @@ constructor( hydrateSystemUiState() collectFalsingSignals() hydrateWindowFocus() hydrateInteractionState() } else { sceneLogger.logFrameworkEnabled( isEnabled = false, Loading Loading @@ -376,6 +380,46 @@ constructor( } } /** Keeps the interaction state of [CentralSurfaces] up-to-date. */ private fun hydrateInteractionState() { applicationScope.launch { deviceEntryInteractor.isUnlocked .map { !it } .flatMapLatest { isDeviceLocked -> if (isDeviceLocked) { sceneInteractor.transitionState .mapNotNull { it as? ObservableTransitionState.Idle } .map { it.scene } .distinctUntilChanged() .map { sceneKey -> when (sceneKey) { // When locked, showing the lockscreen scene should be reported // as "interacting" while showing other scenes should report as // "not interacting". // // This is done here in order to match the legacy // implementation. The real reason why is lost to lore and myth. SceneKey.Lockscreen -> true SceneKey.Bouncer -> false SceneKey.Shade -> false else -> null } } } else { flowOf(null) } } .collect { isInteractingOrNull -> isInteractingOrNull?.let { isInteracting -> centralSurfaces.setInteracting( StatusBarManager.WINDOW_STATUS_BAR, isInteracting, ) } } } } private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) { sceneInteractor.changeScene( scene = SceneModel(targetSceneKey), Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { authenticationInteractor = dagger.Lazy { kosmos.authenticationInteractor }, windowController = mock(), deviceProvisioningInteractor = kosmos.deviceProvisioningInteractor, centralSurfaces = mock(), ) startable.start() Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +226 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.startable import android.app.StatusBarManager import android.os.PowerManager import android.platform.test.annotations.EnableFlags import android.view.Display Loading Loading @@ -48,6 +49,7 @@ import com.android.systemui.scene.shared.model.ObservableTransitionState import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel 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.policy.domain.interactor.deviceProvisioningInteractor Loading @@ -65,6 +67,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never Loading @@ -78,6 +81,7 @@ import org.mockito.MockitoAnnotations class SceneContainerStartableTest : SysuiTestCase() { @Mock private lateinit var windowController: NotificationShadeWindowController @Mock private lateinit var centralSurfaces: CentralSurfaces private val kosmos = testKosmos() private val testScope = kosmos.testScope Loading Loading @@ -115,6 +119,7 @@ class SceneContainerStartableTest : SysuiTestCase() { authenticationInteractor = dagger.Lazy { authenticationInteractor }, windowController = windowController, deviceProvisioningInteractor = kosmos.deviceProvisioningInteractor, centralSurfaces = centralSurfaces, ) } Loading Loading @@ -763,6 +768,227 @@ class SceneContainerStartableTest : SysuiTestCase() { verify(windowController, times(2)).setNotificationShadeFocusable(false) } @Test fun hydrateInteractionState_whileLocked() = testScope.runTest { val transitionStateFlow = prepareState( initialSceneKey = SceneKey.Lockscreen, ) underTest.start() runCurrent() verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Bouncer, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, false, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, true, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Shade, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, false, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces) .setInteracting( StatusBarManager.WINDOW_STATUS_BAR, true, ) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.QuickSettings, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) } @Test fun hydrateInteractionState_whileUnlocked() = testScope.runTest { val transitionStateFlow = prepareState( isDeviceUnlocked = true, initialSceneKey = SceneKey.Gone, ) underTest.start() verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Bouncer, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Shade, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.Lockscreen, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) clearInvocations(centralSurfaces) emulateSceneTransition( transitionStateFlow = transitionStateFlow, toScene = SceneKey.QuickSettings, verifyBeforeTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyDuringTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, ) } private fun TestScope.emulateSceneTransition( transitionStateFlow: MutableStateFlow<ObservableTransitionState>, toScene: SceneKey, verifyBeforeTransition: (() -> Unit)? = null, verifyDuringTransition: (() -> Unit)? = null, verifyAfterTransition: (() -> Unit)? = null, ) { val fromScene = sceneInteractor.desiredScene.value.key sceneInteractor.changeScene(SceneModel(toScene), "reason") runCurrent() verifyBeforeTransition?.invoke() transitionStateFlow.value = ObservableTransitionState.Transition( fromScene = fromScene, toScene = toScene, progress = flowOf(0.5f), isInitiatedByUserInput = true, isUserInputOngoing = flowOf(true), ) runCurrent() verifyDuringTransition?.invoke() transitionStateFlow.value = ObservableTransitionState.Idle( scene = toScene, ) runCurrent() verifyAfterTransition?.invoke() } private fun TestScope.prepareState( isDeviceUnlocked: Boolean = false, isBypassEnabled: Boolean = false, Loading
packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +44 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.startable import android.app.StatusBarManager import com.android.systemui.CoreStartable import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel Loading @@ -42,6 +43,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor import com.android.systemui.util.asIndenting import com.android.systemui.util.printSection Loading Loading @@ -85,6 +87,7 @@ constructor( private val authenticationInteractor: Lazy<AuthenticationInteractor>, private val windowController: NotificationShadeWindowController, private val deviceProvisioningInteractor: DeviceProvisioningInteractor, private val centralSurfaces: CentralSurfaces, ) : CoreStartable { override fun start() { Loading @@ -95,6 +98,7 @@ constructor( hydrateSystemUiState() collectFalsingSignals() hydrateWindowFocus() hydrateInteractionState() } else { sceneLogger.logFrameworkEnabled( isEnabled = false, Loading Loading @@ -376,6 +380,46 @@ constructor( } } /** Keeps the interaction state of [CentralSurfaces] up-to-date. */ private fun hydrateInteractionState() { applicationScope.launch { deviceEntryInteractor.isUnlocked .map { !it } .flatMapLatest { isDeviceLocked -> if (isDeviceLocked) { sceneInteractor.transitionState .mapNotNull { it as? ObservableTransitionState.Idle } .map { it.scene } .distinctUntilChanged() .map { sceneKey -> when (sceneKey) { // When locked, showing the lockscreen scene should be reported // as "interacting" while showing other scenes should report as // "not interacting". // // This is done here in order to match the legacy // implementation. The real reason why is lost to lore and myth. SceneKey.Lockscreen -> true SceneKey.Bouncer -> false SceneKey.Shade -> false else -> null } } } else { flowOf(null) } } .collect { isInteractingOrNull -> isInteractingOrNull?.let { isInteracting -> centralSurfaces.setInteracting( StatusBarManager.WINDOW_STATUS_BAR, isInteracting, ) } } } } private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) { sceneInteractor.changeScene( scene = SceneModel(targetSceneKey), Loading