diff options
10 files changed, 210 insertions, 45 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index 91259a65eff9..3e75cebb1c7d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -34,6 +34,7 @@ import android.hardware.face.FaceSensorPropertiesInternal import android.os.CancellationSignal import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState import com.android.internal.logging.InstanceId.fakeInstanceId import com.android.internal.logging.UiEventLogger import com.android.systemui.Flags as AConfigFlags @@ -55,6 +56,7 @@ import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.keyguard.data.repository.BiometricType import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository @@ -77,6 +79,9 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.testKosmos import com.android.systemui.user.data.model.SelectionStatus @@ -90,6 +95,7 @@ import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent @@ -136,12 +142,12 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { @Captor private lateinit var faceLockoutResetCallback: ArgumentCaptor<FaceManager.LockoutResetCallback> - private val testDispatcher = kosmos.testDispatcher + private val testDispatcher by lazy { kosmos.testDispatcher } - private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository - private val testScope = kosmos.testScope - private val fakeUserRepository = kosmos.fakeUserRepository - private val fakeExecutor = kosmos.fakeExecutor + private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } + private val testScope by lazy { kosmos.testScope } + private val fakeUserRepository by lazy { kosmos.fakeUserRepository } + private val fakeExecutor by lazy { kosmos.fakeExecutor } private lateinit var authStatus: FlowValue<FaceAuthenticationStatus?> private lateinit var detectStatus: FlowValue<FaceDetectionStatus?> private lateinit var authRunning: FlowValue<Boolean?> @@ -149,18 +155,19 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { private lateinit var lockedOut: FlowValue<Boolean?> private lateinit var canFaceAuthRun: FlowValue<Boolean?> private lateinit var authenticated: FlowValue<Boolean?> - private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository - private val deviceEntryFingerprintAuthRepository = + private val biometricSettingsRepository by lazy { kosmos.fakeBiometricSettingsRepository } + private val deviceEntryFingerprintAuthRepository by lazy { kosmos.fakeDeviceEntryFingerprintAuthRepository - private val trustRepository = kosmos.fakeTrustRepository - private val keyguardRepository = kosmos.fakeKeyguardRepository - private val powerInteractor = kosmos.powerInteractor - private val keyguardInteractor = kosmos.keyguardInteractor - private val alternateBouncerInteractor = kosmos.alternateBouncerInteractor - private val displayStateInteractor = kosmos.displayStateInteractor - private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository - private val displayRepository = kosmos.displayRepository - private val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor + } + private val trustRepository by lazy { kosmos.fakeTrustRepository } + private val keyguardRepository by lazy { kosmos.fakeKeyguardRepository } + private val powerInteractor by lazy { kosmos.powerInteractor } + private val keyguardInteractor by lazy { kosmos.keyguardInteractor } + private val alternateBouncerInteractor by lazy { kosmos.alternateBouncerInteractor } + private val displayStateInteractor by lazy { kosmos.displayStateInteractor } + private val bouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository } + private val displayRepository by lazy { kosmos.displayRepository } + private val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor } private lateinit var featureFlags: FakeFeatureFlags private var wasAuthCancelled = false @@ -180,9 +187,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { whenever(bypassController.bypassEnabled).thenReturn(true) underTest = createDeviceEntryFaceAuthRepositoryImpl(faceManager, bypassController) - mSetFlagsRule.disableFlags( - AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR, - ) + if (!SceneContainerFlag.isEnabled) { + mSetFlagsRule.disableFlags( + AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR, + ) + } } private fun createDeviceEntryFaceAuthRepositoryImpl( @@ -227,6 +236,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { powerInteractor, keyguardInteractor, alternateBouncerInteractor, + { kosmos.sceneInteractor }, faceDetectBuffer, faceAuthBuffer, keyguardTransitionInteractor, @@ -547,6 +557,24 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test + @EnableSceneContainer + fun withSceneContainerEnabled_authenticateDoesNotRunWhenKeyguardIsGoingAway() = + testScope.runTest { + testGatingCheckForFaceAuth(sceneContainerEnabled = true) { + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + KeyguardState.LOCKSCREEN, + KeyguardState.UNDEFINED, + value = 0.5f, + transitionState = TransitionState.RUNNING + ), + validateStep = false + ) + runCurrent() + } + } + + @Test fun authenticateDoesNotRunWhenDeviceIsGoingToSleep() = testScope.runTest { testGatingCheckForFaceAuth { @@ -595,6 +623,31 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test + @EnableSceneContainer + fun withSceneContainer_authenticateRunsWhenSecureCameraIsActiveIfBouncerIsShowing() = + testScope.runTest { + initCollectors() + allPreconditionsToRunFaceAuthAreTrue(sceneContainerEnabled = true) + bouncerRepository.setAlternateVisible(false) + + // launch secure camera + keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) + keyguardRepository.setKeyguardOccluded(true) + kosmos.sceneInteractor.snapToScene(Scenes.Lockscreen, "for-test") + runCurrent() + assertThat(canFaceAuthRun()).isFalse() + + // but bouncer is shown after that. + kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "for-test") + kosmos.sceneInteractor.setTransitionState( + MutableStateFlow(ObservableTransitionState.Idle(Scenes.Bouncer)) + ) + runCurrent() + + assertThat(canFaceAuthRun()).isTrue() + } + + @Test fun authenticateDoesNotRunOnUnsupportedPosture() = testScope.runTest { testGatingCheckForFaceAuth { @@ -841,6 +894,24 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test + @EnableSceneContainer + fun withSceneContainer_faceDetectDoesNotRunWhenKeyguardGoingAway() = + testScope.runTest { + testGatingCheckForDetect(sceneContainerEnabled = true) { + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + KeyguardState.LOCKSCREEN, + KeyguardState.UNDEFINED, + value = 0.5f, + transitionState = TransitionState.RUNNING + ), + validateStep = false + ) + runCurrent() + } + } + + @Test fun detectDoesNotRunWhenDeviceSleepingStartingToSleep() = testScope.runTest { testGatingCheckForDetect { @@ -1052,10 +1123,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } private suspend fun TestScope.testGatingCheckForFaceAuth( + sceneContainerEnabled: Boolean = false, gatingCheckModifier: suspend () -> Unit ) { initCollectors() - allPreconditionsToRunFaceAuthAreTrue() + allPreconditionsToRunFaceAuthAreTrue(sceneContainerEnabled) gatingCheckModifier() runCurrent() @@ -1069,7 +1141,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { faceAuthenticateIsNotCalled() // flip the gating check back on. - allPreconditionsToRunFaceAuthAreTrue() + allPreconditionsToRunFaceAuthAreTrue(sceneContainerEnabled) assertThat(underTest.canRunFaceAuth.value).isTrue() faceAuthenticateIsCalled() @@ -1094,10 +1166,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } private suspend fun TestScope.testGatingCheckForDetect( + sceneContainerEnabled: Boolean = false, gatingCheckModifier: suspend () -> Unit ) { initCollectors() - allPreconditionsToRunFaceAuthAreTrue() + allPreconditionsToRunFaceAuthAreTrue(sceneContainerEnabled) // This will stop face auth from running but is required to be false for detect. biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false) @@ -1145,12 +1218,22 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { cancellationSignal.value.setOnCancelListener { wasAuthCancelled = true } } - private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() { + private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue( + sceneContainerEnabled: Boolean = false + ) { fakeExecutor.runAllReady() verify(faceManager, atLeastOnce()) .addLockoutResetCallback(faceLockoutResetCallback.capture()) trustRepository.setCurrentUserTrusted(false) - keyguardRepository.setKeyguardGoingAway(false) + if (sceneContainerEnabled) { + // Keyguard is not going away + kosmos.fakeKeyguardTransitionRepository.sendTransitionStep( + TransitionStep(KeyguardState.OFF, KeyguardState.LOCKSCREEN, value = 1.0f), + validateStep = false + ) + } else { + keyguardRepository.setKeyguardGoingAway(false) + } powerInteractor.setAwakeForTest() biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt index 2b2c121fb79a..aee72de22a24 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt @@ -25,8 +25,11 @@ import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.logging.uiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor +import com.android.systemui.deviceentry.shared.FaceAuthUiEvent import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState @@ -260,6 +263,23 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { } @Test + fun triggersFaceAuthWhenLockscreenIsClicked() = + testScope.runTest { + collectLastValue(underTest.isMenuVisible) + runCurrent() + kosmos.fakeDeviceEntryFaceAuthRepository.canRunFaceAuth.value = true + + underTest.onClick(100.0f, 100.0f) + runCurrent() + + val runningAuthRequest = + kosmos.fakeDeviceEntryFaceAuthRepository.runningAuthRequest.value + assertThat(runningAuthRequest?.first) + .isEqualTo(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED) + assertThat(runningAuthRequest?.second).isEqualTo(true) + } + + @Test fun showMenu_leaveLockscreen_returnToLockscreen_menuNotVisible() = testScope.runTest { val isMenuVisible by collectLastValue(underTest.isMenuVisible) @@ -302,6 +322,7 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { broadcastDispatcher = fakeBroadcastDispatcher, accessibilityManager = kosmos.accessibilityManagerWrapper, pulsingGestureListener = kosmos.pulsingGestureListener, + faceAuthInteractor = kosmos.deviceEntryFaceAuthInteractor, ) setUpState() } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt index 9460eaf8abca..d288ccee2ae8 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt @@ -57,7 +57,10 @@ import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.log.SessionTracker import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.scene.shared.model.Scenes.Bouncer import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository @@ -159,6 +162,7 @@ constructor( private val powerInteractor: PowerInteractor, private val keyguardInteractor: KeyguardInteractor, private val alternateBouncerInteractor: AlternateBouncerInteractor, + private val sceneInteractor: dagger.Lazy<SceneInteractor>, @FaceDetectTableLog private val faceDetectLog: TableLogBuffer, @FaceAuthTableLog private val faceAuthLog: TableLogBuffer, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, @@ -385,7 +389,16 @@ constructor( biometricSettingsRepository.isFaceAuthEnrolledAndEnabled, "isFaceAuthEnrolledAndEnabled" ), - Pair(keyguardRepository.isKeyguardGoingAway.isFalse(), "keyguardNotGoingAway"), + Pair( + if (SceneContainerFlag.isEnabled) { + keyguardTransitionInteractor + .isInTransitionWhere(toStatePredicate = { it == KeyguardState.UNDEFINED }) + .isFalse() + } else { + keyguardRepository.isKeyguardGoingAway.isFalse() + }, + "keyguardNotGoingAway" + ), Pair( keyguardTransitionInteractor .isInTransitionWhere(toStatePredicate = KeyguardState::deviceIsAsleepInState) @@ -397,7 +410,11 @@ constructor( .isFalse() .or( alternateBouncerInteractor.isVisible.or( - keyguardInteractor.primaryBouncerShowing + if (SceneContainerFlag.isEnabled) { + sceneInteractor.get().transitionState.map { it.isIdle(Bouncer) } + } else { + keyguardInteractor.primaryBouncerShowing + } ) ), "secureCameraNotActiveOrAnyBouncerIsShowing" diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt index c536d6b4f6f8..183e0e96e765 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt @@ -46,6 +46,9 @@ import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.res.R +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise @@ -90,6 +93,7 @@ constructor( private val powerInteractor: PowerInteractor, private val biometricSettingsRepository: BiometricSettingsRepository, private val trustManager: TrustManager, + private val sceneInteractor: Lazy<SceneInteractor>, deviceEntryFaceAuthStatusInteractor: DeviceEntryFaceAuthStatusInteractor, ) : DeviceEntryFaceAuthInteractor { @@ -103,9 +107,7 @@ constructor( keyguardUpdateMonitor.setFaceAuthInteractor(this) observeFaceAuthStateUpdates() faceAuthenticationLogger.interactorStarted() - primaryBouncerInteractor - .get() - .isShowing + isBouncerVisible .whenItFlipsToTrue() .onEach { faceAuthenticationLogger.bouncerVisibilityChanged() @@ -181,19 +183,23 @@ constructor( // auth so that the switched user can unlock the device with face auth. userRepository.selectedUser .pairwise() - .onEach { (previous, curr) -> + .filter { (previous, curr) -> val wasSwitching = previous.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS val isSwitching = curr.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS - if (wasSwitching && !isSwitching) { - resetLockedOutState(curr.userInfo.id) - yield() - runFaceAuth( - FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING, - // Fallback to detection if bouncer is not showing so that we can detect a - // face and then show the bouncer to the user if face auth can't run - fallbackToDetect = !primaryBouncerInteractor.get().isBouncerShowing() - ) - } + // User switching was in progress and is complete now. + wasSwitching && !isSwitching + } + .map { (_, curr) -> curr.userInfo.id } + .sample(isBouncerVisible, ::Pair) + .onEach { (userId, isBouncerCurrentlyVisible) -> + resetLockedOutState(userId) + yield() + runFaceAuth( + FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING, + // Fallback to detection if bouncer is not showing so that we can detect a + // face and then show the bouncer to the user if face auth can't run + fallbackToDetect = !isBouncerCurrentlyVisible + ) } .launchIn(applicationScope) @@ -210,6 +216,14 @@ constructor( .launchIn(applicationScope) } + private val isBouncerVisible: Flow<Boolean> by lazy { + if (SceneContainerFlag.isEnabled) { + sceneInteractor.get().transitionState.map { it.isIdle(Scenes.Bouncer) } + } else { + primaryBouncerInteractor.get().isShowing + } + } + private suspend fun resetLockedOutState(currentUserId: Int) { val lockoutMode = facePropertyRepository.getLockoutMode(currentUserId) repository.setLockedOut( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt index cd49c6a4d2e0..4a8ada7f1184 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt @@ -27,6 +27,7 @@ import com.android.internal.logging.UiEventLogger import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.KeyguardRepository @@ -67,6 +68,7 @@ constructor( broadcastDispatcher: BroadcastDispatcher, private val accessibilityManager: AccessibilityManagerWrapper, private val pulsingGestureListener: PulsingGestureListener, + private val faceAuthInteractor: DeviceEntryFaceAuthInteractor, ) { /** Whether the long-press handling feature should be enabled. */ val isLongPressHandlingEnabled: StateFlow<Boolean> = @@ -129,7 +131,8 @@ constructor( } } - /** Notifies that the user has long-pressed on the lock screen. + /** + * Notifies that the user has long-pressed on the lock screen. * * @param isA11yAction: Whether the action was performed as an a11y action */ @@ -174,6 +177,7 @@ constructor( /** Notifies that the lockscreen has been clicked at position [x], [y]. */ fun onClick(x: Float, y: Float) { pulsingGestureListener.onSingleTapUp(x, y) + faceAuthInteractor.onNotificationPanelClicked() } /** Notifies that the lockscreen has been double clicked. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt index 0b7a3ed3a7c2..6aecc0e2b8fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt @@ -22,6 +22,7 @@ import android.hardware.biometrics.BiometricSourceType import android.os.PowerManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState import com.android.keyguard.keyguardUpdateMonitor import com.android.keyguard.trustManager import com.android.systemui.SysuiTestCase @@ -37,6 +38,7 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeFaceWakeUpTriggersConfig import com.android.systemui.deviceentry.shared.FaceAuthUiEvent import com.android.systemui.deviceentry.shared.model.ErrorFaceAuthenticationStatus +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository @@ -52,12 +54,15 @@ import com.android.systemui.log.logcatLogBuffer import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.eq import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -113,6 +118,7 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { powerInteractor, fakeBiometricSettingsRepository, trustManager, + { kosmos.sceneInteractor }, deviceEntryFaceAuthStatusInteractor, ) } @@ -279,6 +285,22 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { } @Test + @EnableSceneContainer + fun withSceneContainerEnabled_faceAuthIsRequestedWhenPrimaryBouncerIsVisible() = + testScope.runTest { + underTest.start() + + kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "for-test") + kosmos.sceneInteractor.setTransitionState( + MutableStateFlow(ObservableTransitionState.Idle(Scenes.Bouncer)) + ) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN, false)) + } + + @Test fun faceAuthIsRequestedWhenAlternateBouncerIsVisible() = testScope.runTest { underTest.start() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index fc7f69319261..d13419eed281 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.animation.Expandable import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.shared.model.Icon import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.dock.DockManagerFake import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.flags.FakeFeatureFlags @@ -152,9 +153,7 @@ class KeyguardBottomAreaViewModelTest(flags: FlagsParameterization) : SysuiTestC dockManager = DockManagerFake() biometricSettingsRepository = FakeBiometricSettingsRepository() val featureFlags = - FakeFeatureFlags().apply { - set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false) - } + FakeFeatureFlags().apply { set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false) } val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags) val keyguardInteractor = withDeps.keyguardInteractor @@ -223,6 +222,7 @@ class KeyguardBottomAreaViewModelTest(flags: FlagsParameterization) : SysuiTestC broadcastDispatcher = broadcastDispatcher, accessibilityManager = accessibilityManager, pulsingGestureListener = kosmos.pulsingGestureListener, + faceAuthInteractor = kosmos.deviceEntryFaceAuthInteractor, ) underTest = KeyguardBottomAreaViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt index b9be04dc0a32..3dfe0eea500f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt @@ -33,6 +33,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.mockito.mock import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -57,6 +58,7 @@ val Kosmos.deviceEntryFaceAuthInteractor by powerInteractor = powerInteractor, biometricSettingsRepository = biometricSettingsRepository, trustManager = trustManager, + sceneInteractor = { sceneInteractor }, deviceEntryFaceAuthStatusInteractor = deviceEntryFaceAuthStatusInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt index 73799b63a6fc..769612c988ba 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt @@ -20,6 +20,7 @@ import android.content.applicationContext import android.view.accessibility.accessibilityManagerWrapper import com.android.internal.logging.uiEventLogger import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos @@ -38,5 +39,6 @@ val Kosmos.keyguardTouchHandlingInteractor by broadcastDispatcher = broadcastDispatcher, accessibilityManager = accessibilityManagerWrapper, pulsingGestureListener = pulsingGestureListener, + faceAuthInteractor = deviceEntryFaceAuthInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt index ae8b411a4b95..f84c3bdfdaf1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt @@ -24,7 +24,7 @@ import com.android.systemui.scene.data.repository.sceneContainerRepository import com.android.systemui.scene.domain.resolver.sceneFamilyResolvers import com.android.systemui.scene.shared.logger.sceneLogger -val Kosmos.sceneInteractor by +val Kosmos.sceneInteractor: SceneInteractor by Kosmos.Fixture { SceneInteractor( applicationScope = applicationCoroutineScope, |