Loading packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +16 −7 Original line number Diff line number Diff line Loading @@ -103,8 +103,11 @@ constructor( initialValue = false, ) // Authenticated by a TrustAgent like trusted device, location, etc or by face auth. private val passivelyAuthenticated = /** * Whether the user is currently authenticated by a TrustAgent like trusted device, location, * etc., or by face auth. */ private val isPassivelyAuthenticated = merge( trustRepository.isCurrentUserTrusted, deviceEntryFaceAuthRepository.isAuthenticated, Loading @@ -117,25 +120,31 @@ constructor( * mechanism like face or trust manager. This returns `false` whenever the lockscreen has been * dismissed. * * A value of `null` is meaningless and is used as placeholder while the actual value is still * being loaded in the background. * * Note: `true` doesn't mean the lockscreen is visible. It may be occluded or covered by other * UI. */ val canSwipeToEnter = val canSwipeToEnter: StateFlow<Boolean?> = combine( // This is true when the user has chosen to show the lockscreen but has not made it // secure. authenticationInteractor.authenticationMethod.map { it == AuthenticationMethodModel.None && repository.isLockscreenEnabled() }, passivelyAuthenticated, isPassivelyAuthenticated, isDeviceEntered ) { isSwipeAuthMethod, passivelyAuthenticated, isDeviceEntered -> (isSwipeAuthMethod || passivelyAuthenticated) && !isDeviceEntered ) { isSwipeAuthMethod, isPassivelyAuthenticated, isDeviceEntered -> (isSwipeAuthMethod || isPassivelyAuthenticated) && !isDeviceEntered } .stateIn( scope = applicationScope, started = SharingStarted.Eagerly, initialValue = false, // Starts as null to prevent downstream collectors from falsely assuming that the // user can or cannot swipe to enter the device while the real value is being loaded // from upstream data sources. initialValue = null, ) /** Loading packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +18 −10 Original line number Diff line number Diff line Loading @@ -146,19 +146,21 @@ constructor( isAnySimLocked -> { switchToScene( targetSceneKey = SceneKey.Bouncer, loggingReason = "Need to authenticate locked sim card." loggingReason = "Need to authenticate locked SIM card." ) } isUnlocked && !canSwipeToEnter -> { isUnlocked && canSwipeToEnter == false -> { switchToScene( targetSceneKey = SceneKey.Gone, loggingReason = "Sim cards are unlocked." loggingReason = "All SIM cards unlocked and device already" + " unlocked and lockscreen doesn't require a swipe to dismiss." ) } else -> { switchToScene( targetSceneKey = SceneKey.Lockscreen, loggingReason = "Sim cards are unlocked." loggingReason = "All SIM cards unlocked and device still locked" + " or lockscreen still requires a swipe to dismiss." ) } } Loading Loading @@ -205,11 +207,17 @@ constructor( // when the user is passively authenticated, the false value here // when the unlock state changes indicates this is an active // authentication attempt. if (isBypassEnabled || !canSwipeToEnter) when { isBypassEnabled -> SceneKey.Gone to "device has been unlocked on lockscreen with bypass" + " enabled" canSwipeToEnter == false -> SceneKey.Gone to "device has been unlocked on lockscreen with either " + "bypass enabled or using an active authentication mechanism" else null "device has been unlocked on lockscreen using an active" + " authentication mechanism" else -> null } // Not on lockscreen or bouncer, so remain in the current scene. else -> null } Loading @@ -232,7 +240,7 @@ constructor( } else { val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value val isUnlocked = deviceEntryInteractor.isUnlocked.value if (isUnlocked && !canSwipeToEnter) { if (isUnlocked && canSwipeToEnter == false) { switchToScene( targetSceneKey = SceneKey.Gone, loggingReason = Loading packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt +2 −2 Original line number Diff line number Diff line Loading @@ -66,10 +66,10 @@ constructor( private fun upDestinationSceneKey( isUnlocked: Boolean, canSwipeToDismiss: Boolean, canSwipeToDismiss: Boolean?, ): SceneKey { return when { canSwipeToDismiss -> SceneKey.Lockscreen canSwipeToDismiss == true -> SceneKey.Lockscreen isUnlocked -> SceneKey.Gone else -> SceneKey.Lockscreen } Loading packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt +8 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository import com.android.systemui.keyguard.data.repository.FakeTrustRepository Loading Loading @@ -55,6 +56,13 @@ class DeviceEntryInteractorTest : SysuiTestCase() { trustRepository = trustRepository, ) @Test fun canSwipeToEnter_startsNull() = testScope.runTest { val values by collectValues(underTest.canSwipeToEnter) assertThat(values[0]).isNull() } @Test fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() = testScope.runTest { Loading packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +4 −2 Original line number Diff line number Diff line Loading @@ -61,7 +61,6 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import junit.framework.Assert.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -272,6 +271,9 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { .isTrue() } @Test fun startsInLockscreenScene() = testScope.runTest { assertCurrentScene(SceneKey.Lockscreen) } @Test fun clickLockButtonAndEnterCorrectPin_unlocksDevice() = testScope.runTest { Loading Loading @@ -336,7 +338,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { testScope.runTest { val upDestinationSceneKey by collectLastValue(shadeSceneViewModel.upDestinationSceneKey) setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true) assertTrue(deviceEntryInteractor.canSwipeToEnter.value) assertThat(deviceEntryInteractor.canSwipeToEnter.value).isTrue() assertCurrentScene(SceneKey.Lockscreen) // Emulate a user swipe to dismiss the lockscreen. Loading Loading
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +16 −7 Original line number Diff line number Diff line Loading @@ -103,8 +103,11 @@ constructor( initialValue = false, ) // Authenticated by a TrustAgent like trusted device, location, etc or by face auth. private val passivelyAuthenticated = /** * Whether the user is currently authenticated by a TrustAgent like trusted device, location, * etc., or by face auth. */ private val isPassivelyAuthenticated = merge( trustRepository.isCurrentUserTrusted, deviceEntryFaceAuthRepository.isAuthenticated, Loading @@ -117,25 +120,31 @@ constructor( * mechanism like face or trust manager. This returns `false` whenever the lockscreen has been * dismissed. * * A value of `null` is meaningless and is used as placeholder while the actual value is still * being loaded in the background. * * Note: `true` doesn't mean the lockscreen is visible. It may be occluded or covered by other * UI. */ val canSwipeToEnter = val canSwipeToEnter: StateFlow<Boolean?> = combine( // This is true when the user has chosen to show the lockscreen but has not made it // secure. authenticationInteractor.authenticationMethod.map { it == AuthenticationMethodModel.None && repository.isLockscreenEnabled() }, passivelyAuthenticated, isPassivelyAuthenticated, isDeviceEntered ) { isSwipeAuthMethod, passivelyAuthenticated, isDeviceEntered -> (isSwipeAuthMethod || passivelyAuthenticated) && !isDeviceEntered ) { isSwipeAuthMethod, isPassivelyAuthenticated, isDeviceEntered -> (isSwipeAuthMethod || isPassivelyAuthenticated) && !isDeviceEntered } .stateIn( scope = applicationScope, started = SharingStarted.Eagerly, initialValue = false, // Starts as null to prevent downstream collectors from falsely assuming that the // user can or cannot swipe to enter the device while the real value is being loaded // from upstream data sources. initialValue = null, ) /** Loading
packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +18 −10 Original line number Diff line number Diff line Loading @@ -146,19 +146,21 @@ constructor( isAnySimLocked -> { switchToScene( targetSceneKey = SceneKey.Bouncer, loggingReason = "Need to authenticate locked sim card." loggingReason = "Need to authenticate locked SIM card." ) } isUnlocked && !canSwipeToEnter -> { isUnlocked && canSwipeToEnter == false -> { switchToScene( targetSceneKey = SceneKey.Gone, loggingReason = "Sim cards are unlocked." loggingReason = "All SIM cards unlocked and device already" + " unlocked and lockscreen doesn't require a swipe to dismiss." ) } else -> { switchToScene( targetSceneKey = SceneKey.Lockscreen, loggingReason = "Sim cards are unlocked." loggingReason = "All SIM cards unlocked and device still locked" + " or lockscreen still requires a swipe to dismiss." ) } } Loading Loading @@ -205,11 +207,17 @@ constructor( // when the user is passively authenticated, the false value here // when the unlock state changes indicates this is an active // authentication attempt. if (isBypassEnabled || !canSwipeToEnter) when { isBypassEnabled -> SceneKey.Gone to "device has been unlocked on lockscreen with bypass" + " enabled" canSwipeToEnter == false -> SceneKey.Gone to "device has been unlocked on lockscreen with either " + "bypass enabled or using an active authentication mechanism" else null "device has been unlocked on lockscreen using an active" + " authentication mechanism" else -> null } // Not on lockscreen or bouncer, so remain in the current scene. else -> null } Loading @@ -232,7 +240,7 @@ constructor( } else { val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value val isUnlocked = deviceEntryInteractor.isUnlocked.value if (isUnlocked && !canSwipeToEnter) { if (isUnlocked && canSwipeToEnter == false) { switchToScene( targetSceneKey = SceneKey.Gone, loggingReason = Loading
packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt +2 −2 Original line number Diff line number Diff line Loading @@ -66,10 +66,10 @@ constructor( private fun upDestinationSceneKey( isUnlocked: Boolean, canSwipeToDismiss: Boolean, canSwipeToDismiss: Boolean?, ): SceneKey { return when { canSwipeToDismiss -> SceneKey.Lockscreen canSwipeToDismiss == true -> SceneKey.Lockscreen isUnlocked -> SceneKey.Gone else -> SceneKey.Lockscreen } Loading
packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt +8 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository import com.android.systemui.keyguard.data.repository.FakeTrustRepository Loading Loading @@ -55,6 +56,13 @@ class DeviceEntryInteractorTest : SysuiTestCase() { trustRepository = trustRepository, ) @Test fun canSwipeToEnter_startsNull() = testScope.runTest { val values by collectValues(underTest.canSwipeToEnter) assertThat(values[0]).isNull() } @Test fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() = testScope.runTest { Loading
packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +4 −2 Original line number Diff line number Diff line Loading @@ -61,7 +61,6 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import junit.framework.Assert.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -272,6 +271,9 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { .isTrue() } @Test fun startsInLockscreenScene() = testScope.runTest { assertCurrentScene(SceneKey.Lockscreen) } @Test fun clickLockButtonAndEnterCorrectPin_unlocksDevice() = testScope.runTest { Loading Loading @@ -336,7 +338,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { testScope.runTest { val upDestinationSceneKey by collectLastValue(shadeSceneViewModel.upDestinationSceneKey) setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true) assertTrue(deviceEntryInteractor.canSwipeToEnter.value) assertThat(deviceEntryInteractor.canSwipeToEnter.value).isTrue() assertCurrentScene(SceneKey.Lockscreen) // Emulate a user swipe to dismiss the lockscreen. Loading