Loading packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt +22 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.testKosmos import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.fakeUserRepository Loading Loading @@ -115,6 +117,7 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { { sceneInteractor }, deviceEntryFaceAuthStatusInteractor, cameraSensorPrivacyInteractor, mobileConnectionsRepository, ) } } Loading Loading @@ -864,6 +867,25 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { .isSameInstanceAs(faceAuthRepository.isAuthenticated) } @Test fun faceAuthIsRequestedOnSimPinSuccess() = kosmos.runTest { underTest.start() runCurrent() // no auth request when the SIM is secure (requires pin) fakeMobileConnectionsRepository.isAnySimSecure.value = true runCurrent() assertThat(faceAuthRepository.runningAuthRequest.value).isNull() // auth request when the SIM is no longer secure (successful pin!) fakeMobileConnectionsRepository.isAnySimSecure.value = false runCurrent() assertThat(faceAuthRepository.runningAuthRequest.value) .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_SIM_PIN_SUCCESS, true)) } companion object { private const val primaryUserId = 1 private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY) Loading packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt +17 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise Loading Loading @@ -110,6 +111,7 @@ constructor( private val sceneInteractor: Lazy<SceneInteractor>, deviceEntryFaceAuthStatusInteractor: DeviceEntryFaceAuthStatusInteractor, cameraSensorPrivacyInteractor: CameraSensorPrivacyInteractor, private val mobileConnectionsRepository: MobileConnectionsRepository, ) : DeviceEntryFaceAuthInteractor { private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() Loading Loading @@ -198,6 +200,13 @@ constructor( } .launchIn(applicationScope) mobileConnectionsRepository.isAnySimSecure .whenItFlipsToFalse() .onEach { runFaceAuth(FaceAuthUiEvent.FACE_AUTH_SIM_PIN_SUCCESS, fallbackToDetect = true) } .launchIn(applicationScope) deviceEntryFingerprintAuthInteractor.isLockedOut .sample(biometricSettingsRepository.isFaceAuthEnrolledAndEnabled, ::Pair) .filter { (_, faceEnabledAndEnrolled) -> Loading Loading @@ -484,3 +493,11 @@ private fun Flow<Boolean>.whenItFlipsToTrue(): Flow<Boolean> { .filter { pair -> !pair.previousValue && pair.newValue } .map { it.newValue } } // Extension method that filters a generic Boolean flow to one that emits // whenever there is flip from true -> false private fun Flow<Boolean>.whenItFlipsToFalse(): Flow<Boolean> { return this.pairwise() .filter { pair -> pair.previousValue && !pair.newValue } .map { it.newValue } } packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt +4 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.POSTURE_C import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.SIM_PIN_SUCCESS import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.STARTED_WAKING_UP import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.STRONG_AUTH_ALLOWED_CHANGED import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.TRUST_DISABLED Loading Loading @@ -133,6 +134,7 @@ private object InternalFaceAuthReasons { const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed." const val DISPLAY_OFF = "Face auth stopped due to display state OFF." const val CAMERA_AVAILABLE_CHANGED = "Face auth started due to the available camera changed" const val SIM_PIN_SUCCESS = "Face auth started due to SIM pin success" } /** Loading Loading @@ -226,7 +228,8 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) : @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION), @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF), @UiEvent(doc = CAMERA_AVAILABLE_CHANGED) FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED); FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED), @UiEvent(doc = SIM_PIN_SUCCESS) FACE_AUTH_SIM_PIN_SUCCESS(2403, SIM_PIN_SUCCESS); override fun getId(): Int = this.id Loading packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ 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.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.mockito.mock Loading @@ -59,5 +60,6 @@ val Kosmos.deviceEntryFaceAuthInteractor by sceneInteractor = { sceneInteractor }, deviceEntryFaceAuthStatusInteractor = deviceEntryFaceAuthStatusInteractor, cameraSensorPrivacyInteractor = cameraSensorPrivacyInteractor, mobileConnectionsRepository = mobileConnectionsRepository, ) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt +22 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.testKosmos import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.fakeUserRepository Loading Loading @@ -115,6 +117,7 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { { sceneInteractor }, deviceEntryFaceAuthStatusInteractor, cameraSensorPrivacyInteractor, mobileConnectionsRepository, ) } } Loading Loading @@ -864,6 +867,25 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { .isSameInstanceAs(faceAuthRepository.isAuthenticated) } @Test fun faceAuthIsRequestedOnSimPinSuccess() = kosmos.runTest { underTest.start() runCurrent() // no auth request when the SIM is secure (requires pin) fakeMobileConnectionsRepository.isAnySimSecure.value = true runCurrent() assertThat(faceAuthRepository.runningAuthRequest.value).isNull() // auth request when the SIM is no longer secure (successful pin!) fakeMobileConnectionsRepository.isAnySimSecure.value = false runCurrent() assertThat(faceAuthRepository.runningAuthRequest.value) .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_SIM_PIN_SUCCESS, true)) } companion object { private const val primaryUserId = 1 private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY) Loading
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt +17 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise Loading Loading @@ -110,6 +111,7 @@ constructor( private val sceneInteractor: Lazy<SceneInteractor>, deviceEntryFaceAuthStatusInteractor: DeviceEntryFaceAuthStatusInteractor, cameraSensorPrivacyInteractor: CameraSensorPrivacyInteractor, private val mobileConnectionsRepository: MobileConnectionsRepository, ) : DeviceEntryFaceAuthInteractor { private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() Loading Loading @@ -198,6 +200,13 @@ constructor( } .launchIn(applicationScope) mobileConnectionsRepository.isAnySimSecure .whenItFlipsToFalse() .onEach { runFaceAuth(FaceAuthUiEvent.FACE_AUTH_SIM_PIN_SUCCESS, fallbackToDetect = true) } .launchIn(applicationScope) deviceEntryFingerprintAuthInteractor.isLockedOut .sample(biometricSettingsRepository.isFaceAuthEnrolledAndEnabled, ::Pair) .filter { (_, faceEnabledAndEnrolled) -> Loading Loading @@ -484,3 +493,11 @@ private fun Flow<Boolean>.whenItFlipsToTrue(): Flow<Boolean> { .filter { pair -> !pair.previousValue && pair.newValue } .map { it.newValue } } // Extension method that filters a generic Boolean flow to one that emits // whenever there is flip from true -> false private fun Flow<Boolean>.whenItFlipsToFalse(): Flow<Boolean> { return this.pairwise() .filter { pair -> pair.previousValue && !pair.newValue } .map { it.newValue } }
packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt +4 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.POSTURE_C import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.SIM_PIN_SUCCESS import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.STARTED_WAKING_UP import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.STRONG_AUTH_ALLOWED_CHANGED import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.TRUST_DISABLED Loading Loading @@ -133,6 +134,7 @@ private object InternalFaceAuthReasons { const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed." const val DISPLAY_OFF = "Face auth stopped due to display state OFF." const val CAMERA_AVAILABLE_CHANGED = "Face auth started due to the available camera changed" const val SIM_PIN_SUCCESS = "Face auth started due to SIM pin success" } /** Loading Loading @@ -226,7 +228,8 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) : @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION), @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF), @UiEvent(doc = CAMERA_AVAILABLE_CHANGED) FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED); FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED), @UiEvent(doc = SIM_PIN_SUCCESS) FACE_AUTH_SIM_PIN_SUCCESS(2403, SIM_PIN_SUCCESS); override fun getId(): Int = this.id Loading
packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ 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.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.mockito.mock Loading @@ -59,5 +60,6 @@ val Kosmos.deviceEntryFaceAuthInteractor by sceneInteractor = { sceneInteractor }, deviceEntryFaceAuthStatusInteractor = deviceEntryFaceAuthStatusInteractor, cameraSensorPrivacyInteractor = cameraSensorPrivacyInteractor, mobileConnectionsRepository = mobileConnectionsRepository, ) }