Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import com.android.systemui.classifier.falsingManager import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic Loading Loading @@ -289,6 +290,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { centralSurfaces = mock(), headsUpInteractor = kosmos.headsUpNotificationInteractor, occlusionInteractor = kosmos.sceneContainerOcclusionInteractor, faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor, ) startable.start() Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +53 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.falsingManager import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository Loading Loading @@ -133,6 +134,7 @@ class SceneContainerStartableTest : SysuiTestCase() { centralSurfaces = centralSurfaces, headsUpInteractor = kosmos.headsUpNotificationInteractor, occlusionInteractor = kosmos.sceneContainerOcclusionInteractor, faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor, ) } Loading Loading @@ -472,7 +474,7 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test fun doesNotSwitchToGoneWhenDeviceStartsToWakeUp_authMethodSecure() = fun doesNotSwitchToGone_whenDeviceStartsToWakeUp_authMethodSecure() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) prepareState( Loading @@ -486,6 +488,34 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) } @Test fun doesNotSwitchToGone_whenDeviceStartsToWakeUp_ifAlreadyTransitioningToLockscreen() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val transitioningTo by collectLastValue(sceneInteractor.transitioningTo) val transitionStateFlow = prepareState( isDeviceUnlocked = true, initialSceneKey = Scenes.Gone, authenticationMethod = AuthenticationMethodModel.Pin, ) transitionStateFlow.value = ObservableTransitionState.Transition( fromScene = Scenes.Gone, toScene = Scenes.Lockscreen, progress = flowOf(0.1f), isInitiatedByUserInput = false, isUserInputOngoing = flowOf(false), ) assertThat(currentSceneKey).isEqualTo(Scenes.Gone) assertThat(transitioningTo).isEqualTo(Scenes.Lockscreen) underTest.start() powerInteractor.setAwakeForTest() assertThat(currentSceneKey).isEqualTo(Scenes.Gone) assertThat(transitioningTo).isEqualTo(Scenes.Lockscreen) } @Test fun switchToGoneWhenDeviceStartsToWakeUp_authMethodSecure_deviceUnlocked() = testScope.runTest { Loading Loading @@ -1051,6 +1081,28 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentScene).isEqualTo(Scenes.Lockscreen) } @Test fun handleBouncerOverscroll() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) val transitionStateFlow = prepareState() underTest.start() emulateSceneTransition(transitionStateFlow, toScene = Scenes.Bouncer) assertThat(currentScene).isEqualTo(Scenes.Bouncer) transitionStateFlow.value = ObservableTransitionState.Transition( fromScene = Scenes.Bouncer, toScene = Scenes.Lockscreen, progress = flowOf(-0.4f), isInitiatedByUserInput = true, isUserInputOngoing = flowOf(true), ) runCurrent() assertThat(kosmos.fakeDeviceEntryFaceAuthRepository.isAuthRunning.value).isTrue() } private fun TestScope.emulateSceneTransition( transitionStateFlow: MutableStateFlow<ObservableTransitionState>, toScene: SceneKey, Loading packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +44 −7 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.model.SceneContainerPlugin Loading Loading @@ -63,6 +64,8 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map Loading Loading @@ -96,6 +99,7 @@ constructor( private val centralSurfaces: CentralSurfaces, private val headsUpInteractor: HeadsUpNotificationInteractor, private val occlusionInteractor: SceneContainerOcclusionInteractor, private val faceUnlockInteractor: DeviceEntryFaceAuthInteractor, ) : CoreStartable { override fun start() { Loading @@ -108,6 +112,7 @@ constructor( respondToFalsingDetections() hydrateWindowFocus() hydrateInteractionState() handleBouncerOverscroll() } else { sceneLogger.logFrameworkEnabled( isEnabled = false, Loading Loading @@ -227,7 +232,7 @@ constructor( is ObservableTransitionState.Idle -> setOf(transitionState.scene) is ObservableTransitionState.Transition -> setOf( transitionState.progress, transitionState.fromScene, transitionState.toScene, ) } Loading Loading @@ -294,12 +299,17 @@ constructor( val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value val isUnlocked = deviceEntryInteractor.isUnlocked.value if (isUnlocked && canSwipeToEnter == false) { val isTransitioningToLockscreen = sceneInteractor.transitioningTo.value == Scenes.Lockscreen if (!isTransitioningToLockscreen) { switchToScene( targetSceneKey = Scenes.Gone, loggingReason = "device is waking up while unlocked without the ability" + " to swipe up on lockscreen to enter.", "device is waking up while unlocked without the ability to" + " swipe up on lockscreen to enter and not on or" + " transitioning to, the lockscreen scene.", ) } } else if ( authenticationInteractor.get().getAuthenticationMethod() == AuthenticationMethodModel.Sim Loading Loading @@ -456,6 +466,33 @@ constructor( } } private fun handleBouncerOverscroll() { applicationScope.launch { sceneInteractor.transitionState // Only consider transitions. .filterIsInstance<ObservableTransitionState.Transition>() // Only consider user-initiated (e.g. drags) that go from bouncer to lockscreen. .filter { transition -> transition.fromScene == Scenes.Bouncer && transition.toScene == Scenes.Lockscreen && transition.isInitiatedByUserInput } .flatMapLatest { it.progress } // Figure out the direction of scrolling. .map { progress -> when { progress > 0 -> 1 progress < 0 -> -1 else -> 0 } } .distinctUntilChanged() // Only consider negative scrolling, AKA overscroll. .filter { it == -1 } .collect { faceUnlockInteractor.onSwipeUpOnBouncer() } } } private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) { sceneInteractor.changeScene( toScene = targetSceneKey, Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import com.android.systemui.classifier.falsingManager import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic Loading Loading @@ -289,6 +290,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { centralSurfaces = mock(), headsUpInteractor = kosmos.headsUpNotificationInteractor, occlusionInteractor = kosmos.sceneContainerOcclusionInteractor, faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor, ) startable.start() Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +53 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.falsingManager import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository Loading Loading @@ -133,6 +134,7 @@ class SceneContainerStartableTest : SysuiTestCase() { centralSurfaces = centralSurfaces, headsUpInteractor = kosmos.headsUpNotificationInteractor, occlusionInteractor = kosmos.sceneContainerOcclusionInteractor, faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor, ) } Loading Loading @@ -472,7 +474,7 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test fun doesNotSwitchToGoneWhenDeviceStartsToWakeUp_authMethodSecure() = fun doesNotSwitchToGone_whenDeviceStartsToWakeUp_authMethodSecure() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) prepareState( Loading @@ -486,6 +488,34 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) } @Test fun doesNotSwitchToGone_whenDeviceStartsToWakeUp_ifAlreadyTransitioningToLockscreen() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val transitioningTo by collectLastValue(sceneInteractor.transitioningTo) val transitionStateFlow = prepareState( isDeviceUnlocked = true, initialSceneKey = Scenes.Gone, authenticationMethod = AuthenticationMethodModel.Pin, ) transitionStateFlow.value = ObservableTransitionState.Transition( fromScene = Scenes.Gone, toScene = Scenes.Lockscreen, progress = flowOf(0.1f), isInitiatedByUserInput = false, isUserInputOngoing = flowOf(false), ) assertThat(currentSceneKey).isEqualTo(Scenes.Gone) assertThat(transitioningTo).isEqualTo(Scenes.Lockscreen) underTest.start() powerInteractor.setAwakeForTest() assertThat(currentSceneKey).isEqualTo(Scenes.Gone) assertThat(transitioningTo).isEqualTo(Scenes.Lockscreen) } @Test fun switchToGoneWhenDeviceStartsToWakeUp_authMethodSecure_deviceUnlocked() = testScope.runTest { Loading Loading @@ -1051,6 +1081,28 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentScene).isEqualTo(Scenes.Lockscreen) } @Test fun handleBouncerOverscroll() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) val transitionStateFlow = prepareState() underTest.start() emulateSceneTransition(transitionStateFlow, toScene = Scenes.Bouncer) assertThat(currentScene).isEqualTo(Scenes.Bouncer) transitionStateFlow.value = ObservableTransitionState.Transition( fromScene = Scenes.Bouncer, toScene = Scenes.Lockscreen, progress = flowOf(-0.4f), isInitiatedByUserInput = true, isUserInputOngoing = flowOf(true), ) runCurrent() assertThat(kosmos.fakeDeviceEntryFaceAuthRepository.isAuthRunning.value).isTrue() } private fun TestScope.emulateSceneTransition( transitionStateFlow: MutableStateFlow<ObservableTransitionState>, toScene: SceneKey, Loading
packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +44 −7 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.model.SceneContainerPlugin Loading Loading @@ -63,6 +64,8 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map Loading Loading @@ -96,6 +99,7 @@ constructor( private val centralSurfaces: CentralSurfaces, private val headsUpInteractor: HeadsUpNotificationInteractor, private val occlusionInteractor: SceneContainerOcclusionInteractor, private val faceUnlockInteractor: DeviceEntryFaceAuthInteractor, ) : CoreStartable { override fun start() { Loading @@ -108,6 +112,7 @@ constructor( respondToFalsingDetections() hydrateWindowFocus() hydrateInteractionState() handleBouncerOverscroll() } else { sceneLogger.logFrameworkEnabled( isEnabled = false, Loading Loading @@ -227,7 +232,7 @@ constructor( is ObservableTransitionState.Idle -> setOf(transitionState.scene) is ObservableTransitionState.Transition -> setOf( transitionState.progress, transitionState.fromScene, transitionState.toScene, ) } Loading Loading @@ -294,12 +299,17 @@ constructor( val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value val isUnlocked = deviceEntryInteractor.isUnlocked.value if (isUnlocked && canSwipeToEnter == false) { val isTransitioningToLockscreen = sceneInteractor.transitioningTo.value == Scenes.Lockscreen if (!isTransitioningToLockscreen) { switchToScene( targetSceneKey = Scenes.Gone, loggingReason = "device is waking up while unlocked without the ability" + " to swipe up on lockscreen to enter.", "device is waking up while unlocked without the ability to" + " swipe up on lockscreen to enter and not on or" + " transitioning to, the lockscreen scene.", ) } } else if ( authenticationInteractor.get().getAuthenticationMethod() == AuthenticationMethodModel.Sim Loading Loading @@ -456,6 +466,33 @@ constructor( } } private fun handleBouncerOverscroll() { applicationScope.launch { sceneInteractor.transitionState // Only consider transitions. .filterIsInstance<ObservableTransitionState.Transition>() // Only consider user-initiated (e.g. drags) that go from bouncer to lockscreen. .filter { transition -> transition.fromScene == Scenes.Bouncer && transition.toScene == Scenes.Lockscreen && transition.isInitiatedByUserInput } .flatMapLatest { it.progress } // Figure out the direction of scrolling. .map { progress -> when { progress > 0 -> 1 progress < 0 -> -1 else -> 0 } } .distinctUntilChanged() // Only consider negative scrolling, AKA overscroll. .filter { it == -1 } .collect { faceUnlockInteractor.onSwipeUpOnBouncer() } } } private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) { sceneInteractor.changeScene( toScene = targetSceneKey, Loading