From 821c428031f35e417a38a0db8f7a6523c14a7813 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Thu, 3 Aug 2023 20:16:58 -0700 Subject: [PATCH] Provide better API methods that can provide face/fp auth status 1. `isFingerprintAuthUsuallyAllowed` is true when fp is enrolled and is not disabled through device policy 2. `isFingerprintAuthCurrentlyAllowed` is true when `isFingerprintAuthUsuallyAllowed` is true and strong auth flags don't restrict fp auth 3. `isFaceAuthUsuallyAllowed` is true when face is enrolled, not disabled by device policy and enabled in biometricManager 4. `isFaceAuthCurrentlyAllowed` is true when `isFaceAuthUsuallyAllowed` is true and face auth is allowed in current posture and strong auth flags don't prevent face auth from running a. If face auth is class3 then this will rely on strong biometric allowed strong auth flag b. If face auth is not class3 then this will rely on non strong biometric allowed strong auth flag Motivation for the change: 1. Modern arch replacement for methods like KeyguardUpdateMonitor `isUnlockingWithFingerprintAllowed` and `isUnlockingWithBiometricAllowed` 2. `KeyguardUpdateMonitor#isUnlockingWithBiometricAllowed` doesn't actually check for enrollment state, which is the root cause of the bug. 3. In all places where we check if fingerprint is enrolled, we always check if fp is enabled and if fp is allowed by strong auth flags. Same for face as well. Bug: 293472698 Test: atest BouncerMessageRepositoryTest Test: atest AlternateBouncerInteractorTest Test: atest BiometricSettingsRepositoryTest Test: atest DeviceEntryFaceAuthRepositoryTest Change-Id: I9ae5e54aa473ff6c02d551607a3c0907585aa6a6 --- .../data/factory/BouncerMessageFactory.kt | 6 +- .../repository/BouncerMessageRepository.kt | 20 +- .../interactor/AlternateBouncerInteractor.kt | 4 +- .../repository/BiometricSettingsRepository.kt | 101 ++++-- .../DeviceEntryFaceAuthRepository.kt | 32 +- .../data/factory/BouncerMessageFactoryTest.kt | 11 +- .../data/repo/BouncerMessageRepositoryTest.kt | 27 +- .../AlternateBouncerInteractorTest.kt | 21 +- .../BouncerMessageInteractorTest.kt | 23 +- .../BiometricSettingsRepositoryTest.kt | 307 +++++++++++++++--- .../DeviceEntryFaceAuthRepositoryTest.kt | 98 ++---- .../FakeBiometricSettingsRepository.kt | 73 ++--- 12 files changed, 433 insertions(+), 290 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt index 1817ea9024fce..64bf688b3c5de 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt @@ -36,7 +36,6 @@ import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINL import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST -import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R.string.bouncer_face_not_recognized import com.android.systemui.R.string.keyguard_enter_password import com.android.systemui.R.string.keyguard_enter_pattern @@ -80,13 +79,14 @@ import com.android.systemui.R.string.kg_wrong_pin_try_again import com.android.systemui.bouncer.shared.model.BouncerMessageModel import com.android.systemui.bouncer.shared.model.Message import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import javax.inject.Inject @SysUISingleton class BouncerMessageFactory @Inject constructor( - private val updateMonitor: KeyguardUpdateMonitor, + private val biometricSettingsRepository: BiometricSettingsRepository, private val securityModel: KeyguardSecurityModel, ) { @@ -99,7 +99,7 @@ constructor( getBouncerMessage( reason, securityModel.getSecurityMode(userId), - updateMonitor.isUnlockingWithFingerprintAllowed + biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value ) return pair?.let { BouncerMessageModel( diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt index 6fb0d4cc5e135..97c1bdb180a16 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt @@ -123,20 +123,11 @@ constructor( fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, ) : BouncerMessageRepository { - private val isFaceEnrolledAndEnabled = - and( - biometricSettingsRepository.isFaceAuthenticationEnabled, - biometricSettingsRepository.isFaceEnrolled - ) - - private val isFingerprintEnrolledAndEnabled = - and( - biometricSettingsRepository.isFingerprintEnabledByDevicePolicy, - biometricSettingsRepository.isFingerprintEnrolled - ) - private val isAnyBiometricsEnabledAndEnrolled = - or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled) + or( + biometricSettingsRepository.isFaceAuthEnrolledAndEnabled, + biometricSettingsRepository.isFingerprintEnrolledAndEnabled, + ) private val wasRebootedForMainlineUpdate get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE @@ -335,8 +326,5 @@ constructor( } } -private fun and(flow: Flow, anotherFlow: Flow) = - flow.combine(anotherFlow) { a, b -> a && b } - private fun or(flow: Flow, anotherFlow: Flow) = flow.combine(anotherFlow) { a, b -> a || b } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt index 98ae54b1340e4..9a7fec1daae0f 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt @@ -83,9 +83,7 @@ constructor( fun canShowAlternateBouncerForFingerprint(): Boolean { return bouncerRepository.alternateBouncerUIAvailable.value && - biometricSettingsRepository.isFingerprintEnrolled.value && - biometricSettingsRepository.isStrongBiometricAllowed.value && - biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value && + biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value && !keyguardUpdateMonitor.isFingerprintLockedOut && !keyguardStateController.isUnlocked && !statusBarStateController.isDozing diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt index ff3e77c46f1c9..682e841c35212 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt @@ -28,6 +28,9 @@ import com.android.internal.widget.LockPatternUtils import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.biometrics.AuthController +import com.android.systemui.biometrics.data.repository.FacePropertyRepository +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow @@ -68,34 +71,32 @@ import kotlinx.coroutines.flow.transformLatest * upstream changes. */ interface BiometricSettingsRepository { - /** Whether any fingerprints are enrolled for the current user. */ - val isFingerprintEnrolled: StateFlow - - /** Whether face authentication is enrolled for the current user. */ - val isFaceEnrolled: Flow + /** + * If the current user can enter the device using fingerprint. This is true if user has enrolled + * fingerprints and fingerprint auth is not disabled through settings/device policy + */ + val isFingerprintEnrolledAndEnabled: StateFlow /** - * Whether face authentication is enabled/disabled based on system settings like device policy, - * biometrics setting. + * If the current user can enter the device using fingerprint, right now. + * + * This returns true if there are no strong auth flags that restrict the user from using + * fingerprint and [isFingerprintEnrolledAndEnabled] is true */ - val isFaceAuthenticationEnabled: Flow + val isFingerprintAuthCurrentlyAllowed: StateFlow /** - * Whether the current user is allowed to use a strong biometric for device entry based on - * Android Security policies. If false, the user may be able to use primary authentication for - * device entry. + * If the current user can use face auth to enter the device. This is true when the user has + * face auth enrolled, and is enabled in settings/device policy. */ - val isStrongBiometricAllowed: StateFlow + val isFaceAuthEnrolledAndEnabled: Flow /** - * Whether the current user is allowed to use a convenience biometric for device entry based on - * Android Security policies. If false, the user may be able to use strong biometric or primary - * authentication for device entry. + * If the current user can use face auth to enter the device right now. This is true when + * [isFaceAuthEnrolledAndEnabled] is true and strong auth settings allow face auth to run and + * face auth is supported by the current device posture. */ - val isNonStrongBiometricAllowed: StateFlow - - /** Whether fingerprint feature is enabled for the current user by the DevicePolicy */ - val isFingerprintEnabledByDevicePolicy: StateFlow + val isFaceAuthCurrentlyAllowed: Flow /** * Whether face authentication is supported for the current device posture. Face auth can be @@ -130,6 +131,8 @@ constructor( @Background backgroundDispatcher: CoroutineDispatcher, biometricManager: BiometricManager?, devicePostureRepository: DevicePostureRepository, + facePropertyRepository: FacePropertyRepository, + fingerprintPropertyRepository: FingerprintPropertyRepository, dumpManager: DumpManager, ) : BiometricSettingsRepository, Dumpable { @@ -165,7 +168,9 @@ constructor( } override fun dump(pw: PrintWriter, args: Array) { - pw.println("isFingerprintEnrolled=${isFingerprintEnrolled.value}") + pw.println("isFingerprintEnrolledAndEnabled=${isFingerprintEnrolledAndEnabled.value}") + pw.println("isFingerprintAuthCurrentlyAllowed=${isFingerprintAuthCurrentlyAllowed.value}") + pw.println("isNonStrongBiometricAllowed=${isNonStrongBiometricAllowed.value}") pw.println("isStrongBiometricAllowed=${isStrongBiometricAllowed.value}") pw.println("isFingerprintEnabledByDevicePolicy=${isFingerprintEnabledByDevicePolicy.value}") } @@ -180,7 +185,7 @@ constructor( user = UserHandle.ALL ) - override val isFingerprintEnrolled: StateFlow = + private val isFingerprintEnrolled: Flow = selectedUserId .flatMapLatest { currentUserId -> conflatedCallbackFlow { @@ -211,7 +216,7 @@ constructor( authController.isFingerprintEnrolled(userRepository.getSelectedUserInfo().id) ) - override val isFaceEnrolled: Flow = + private val isFaceEnrolled: Flow = selectedUserId.flatMapLatest { selectedUserId: Int -> conflatedCallbackFlow { val callback = @@ -245,14 +250,6 @@ constructor( isFaceEnabledByBiometricsManager.map { biometricsEnabledForUser[userInfo.id] ?: false } } - override val isFaceAuthenticationEnabled: Flow - get() = - combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) { - biometricsManagerSetting, - devicePolicySetting -> - biometricsManagerSetting && devicePolicySetting - } - private val isFaceEnabledByDevicePolicy: Flow = combine(selectedUserId, devicePolicyChangedForAllUsers) { userId, _ -> devicePolicyManager.isFaceDisabled(userId) @@ -263,6 +260,13 @@ constructor( .flowOn(backgroundDispatcher) .distinctUntilChanged() + private val isFaceAuthenticationEnabled: Flow = + combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) { + biometricsManagerSetting, + devicePolicySetting -> + biometricsManagerSetting && devicePolicySetting + } + private val isFaceEnabledByBiometricsManager: Flow> = conflatedCallbackFlow { val callback = @@ -283,7 +287,7 @@ constructor( // being registered. .stateIn(scope, SharingStarted.Eagerly, Pair(0, false)) - override val isStrongBiometricAllowed: StateFlow = + private val isStrongBiometricAllowed: StateFlow = strongAuthTracker.isStrongBiometricAllowed.stateIn( scope, SharingStarted.Eagerly, @@ -293,7 +297,7 @@ constructor( ) ) - override val isNonStrongBiometricAllowed: StateFlow = + private val isNonStrongBiometricAllowed: StateFlow = strongAuthTracker.isNonStrongBiometricAllowed.stateIn( scope, SharingStarted.Eagerly, @@ -303,7 +307,19 @@ constructor( ) ) - override val isFingerprintEnabledByDevicePolicy: StateFlow = + private val isFingerprintBiometricAllowed: Flow = + fingerprintPropertyRepository.strength.flatMapLatest { + if (it == SensorStrength.STRONG) isStrongBiometricAllowed + else isNonStrongBiometricAllowed + } + + private val isFaceBiometricsAllowed: Flow = + facePropertyRepository.sensorInfo.flatMapLatest { + if (it?.strength == SensorStrength.STRONG) isStrongBiometricAllowed + else isNonStrongBiometricAllowed + } + + private val isFingerprintEnabledByDevicePolicy: StateFlow = selectedUserId .flatMapLatest { userId -> devicePolicyChangedForAllUsers @@ -319,6 +335,25 @@ constructor( userRepository.getSelectedUserInfo().id ) ) + + override val isFingerprintEnrolledAndEnabled: StateFlow = + isFingerprintEnrolled + .and(isFingerprintEnabledByDevicePolicy) + .stateIn(scope, SharingStarted.Eagerly, false) + + override val isFingerprintAuthCurrentlyAllowed: StateFlow = + isFingerprintEnrolledAndEnabled + .and(isFingerprintBiometricAllowed) + .stateIn(scope, SharingStarted.Eagerly, false) + + override val isFaceAuthEnrolledAndEnabled: Flow + get() = isFaceAuthenticationEnabled.and(isFaceEnrolled) + + override val isFaceAuthCurrentlyAllowed: Flow + get() = + isFaceAuthEnrolledAndEnabled + .and(isFaceBiometricsAllowed) + .and(isFaceAuthSupportedInCurrentPosture) } @OptIn(ExperimentalCoroutinesApi::class) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index 689414711388d..93eb103d74e1f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -26,8 +26,6 @@ import com.android.internal.logging.UiEventLogger import com.android.keyguard.FaceAuthUiEvent import com.android.systemui.Dumpable import com.android.systemui.R -import com.android.systemui.biometrics.data.repository.FacePropertyRepository -import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow @@ -72,7 +70,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -162,7 +159,6 @@ constructor( @FaceAuthTableLog private val faceAuthLog: TableLogBuffer, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val featureFlags: FeatureFlags, - facePropertyRepository: FacePropertyRepository, dumpManager: DumpManager, ) : DeviceEntryFaceAuthRepository, Dumpable { private var authCancellationSignal: CancellationSignal? = null @@ -182,13 +178,6 @@ constructor( override val detectionStatus: Flow get() = _detectionStatus.filterNotNull() - private val isFaceBiometricsAllowed: Flow = - facePropertyRepository.sensorInfo.flatMapLatest { - if (it?.strength == SensorStrength.STRONG) - biometricSettingsRepository.isStrongBiometricAllowed - else biometricSettingsRepository.isNonStrongBiometricAllowed - } - private val _isLockedOut = MutableStateFlow(false) override val isLockedOut: StateFlow = _isLockedOut @@ -313,8 +302,10 @@ constructor( canFaceAuthOrDetectRun(faceDetectLog), logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog), logAndObserve( - isFaceBiometricsAllowed.isFalse().or(trustRepository.isCurrentUserTrusted), - "biometricIsNotAllowedOrCurrentUserIsTrusted", + biometricSettingsRepository.isFaceAuthCurrentlyAllowed + .isFalse() + .or(trustRepository.isCurrentUserTrusted), + "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted", faceDetectLog ), // We don't want to run face detect if fingerprint can be used to unlock the device @@ -346,13 +337,8 @@ constructor( private fun canFaceAuthOrDetectRun(tableLogBuffer: TableLogBuffer): Flow { return listOf( logAndObserve( - biometricSettingsRepository.isFaceEnrolled, - "isFaceEnrolled", - tableLogBuffer - ), - logAndObserve( - biometricSettingsRepository.isFaceAuthenticationEnabled, - "isFaceAuthenticationEnabled", + biometricSettingsRepository.isFaceAuthEnrolledAndEnabled, + "isFaceAuthEnrolledAndEnabled", tableLogBuffer ), logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer), @@ -406,7 +392,11 @@ constructor( "currentUserIsNotTrusted", faceAuthLog ), - logAndObserve(isFaceBiometricsAllowed, "isFaceBiometricsAllowed", faceAuthLog), + logAndObserve( + biometricSettingsRepository.isFaceAuthCurrentlyAllowed, + "isFaceAuthCurrentlyAllowed", + faceAuthLog + ), logAndObserve(isAuthenticated.isFalse(), "faceNotAuthenticated", faceAuthLog), ) .reduce(::and) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt index efae3fe1af2c7..8eb274a65bc4f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt @@ -24,13 +24,12 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Pattern import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT -import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.shared.model.BouncerMessageModel +import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.util.mockito.whenever import com.google.common.truth.StringSubject import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before @@ -39,13 +38,12 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations -@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class BouncerMessageFactoryTest : SysuiTestCase() { private lateinit var underTest: BouncerMessageFactory - @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor + @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository @Mock private lateinit var securityModel: KeyguardSecurityModel @@ -55,7 +53,8 @@ class BouncerMessageFactoryTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) testScope = TestScope() - underTest = BouncerMessageFactory(updateMonitor, securityModel) + biometricSettingsRepository = FakeBiometricSettingsRepository() + underTest = BouncerMessageFactory(biometricSettingsRepository, securityModel) } @Test @@ -167,7 +166,7 @@ class BouncerMessageFactoryTest : SysuiTestCase() { secondaryMessageOverride: String? = null, ): BouncerMessageModel? { whenever(securityModel.getSecurityMode(0)).thenReturn(mode) - whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(fpAuthAllowed) + biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(fpAuthAllowed) return underTest.createFromPromptReason( reason, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt index 2be7d8a43a189..562a8ef512d4f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt @@ -101,14 +101,15 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository() testScope = TestScope() - whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false) + biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false) whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN) underTest = BouncerMessageRepositoryImpl( trustRepository = trustRepository, biometricSettingsRepository = biometricSettingsRepository, updateMonitor = updateMonitor, - bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel), + bouncerMessageFactory = + BouncerMessageFactory(biometricSettingsRepository, securityModel), userRepository = userRepository, fingerprintAuthRepository = fingerprintRepository, systemPropertiesHelper = systemPropertiesHelper @@ -222,8 +223,7 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { whenever(systemPropertiesHelper.get("sys.boot.reason.last")) .thenReturn("reboot,mainline_update") userRepository.setSelectedUserInfo(PRIMARY_USER) - biometricSettingsRepository.setFaceEnrolled(true) - biometricSettingsRepository.setIsFaceAuthEnabled(true) + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) verifyMessagesForAuthFlag( STRONG_AUTH_REQUIRED_AFTER_BOOT to @@ -236,8 +236,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { testScope.runTest { userRepository.setSelectedUserInfo(PRIMARY_USER) trustRepository.setCurrentUserTrustManaged(false) - biometricSettingsRepository.setFaceEnrolled(false) - biometricSettingsRepository.setFingerprintEnrolled(false) + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) verifyMessagesForAuthFlag( STRONG_AUTH_NOT_REQUIRED to null, @@ -258,8 +258,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { fun authFlagsChanges_withTrustManaged_providesDifferentMessages() = testScope.runTest { userRepository.setSelectedUserInfo(PRIMARY_USER) - biometricSettingsRepository.setFaceEnrolled(false) - biometricSettingsRepository.setFingerprintEnrolled(false) + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) trustRepository.setCurrentUserTrustManaged(true) @@ -290,10 +290,9 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { testScope.runTest { userRepository.setSelectedUserInfo(PRIMARY_USER) trustRepository.setCurrentUserTrustManaged(false) - biometricSettingsRepository.setFingerprintEnrolled(false) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) - biometricSettingsRepository.setIsFaceAuthEnabled(true) - biometricSettingsRepository.setFaceEnrolled(true) + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) verifyMessagesForAuthFlag( STRONG_AUTH_NOT_REQUIRED to null, @@ -320,11 +319,9 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { testScope.runTest { userRepository.setSelectedUserInfo(PRIMARY_USER) trustRepository.setCurrentUserTrustManaged(false) - biometricSettingsRepository.setIsFaceAuthEnabled(false) - biometricSettingsRepository.setFaceEnrolled(false) + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false) - biometricSettingsRepository.setFingerprintEnrolled(true) - biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) verifyMessagesForAuthFlag( STRONG_AUTH_NOT_REQUIRED to null, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt index 38e5728f6e706..0d172706b1279 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt @@ -94,9 +94,9 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { } @Test - fun canShowAlternateBouncerForFingerprint_noFingerprintsEnrolled() { + fun canShowAlternateBouncerForFingerprint_ifFingerprintIsNotUsuallyAllowed() { givenCanShowAlternateBouncer() - biometricSettingsRepository.setFingerprintEnrolled(false) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) assertFalse(underTest.canShowAlternateBouncerForFingerprint()) } @@ -104,15 +104,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { @Test fun canShowAlternateBouncerForFingerprint_strongBiometricNotAllowed() { givenCanShowAlternateBouncer() - biometricSettingsRepository.setStrongBiometricAllowed(false) - - assertFalse(underTest.canShowAlternateBouncerForFingerprint()) - } - - @Test - fun canShowAlternateBouncerForFingerprint_devicePolicyDoesNotAllowFingerprint() { - givenCanShowAlternateBouncer() - biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(false) + biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false) assertFalse(underTest.canShowAlternateBouncerForFingerprint()) } @@ -189,14 +181,13 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { private fun givenCanShowAlternateBouncer() { bouncerRepository.setAlternateBouncerUIAvailable(true) - biometricSettingsRepository.setFingerprintEnrolled(true) - biometricSettingsRepository.setStrongBiometricAllowed(true) - biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true) whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false) whenever(keyguardStateController.isUnlocked).thenReturn(false) } private fun givenCannotShowAlternateBouncer() { - biometricSettingsRepository.setFingerprintEnrolled(false) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt index 3ca94aa8e7afa..4089abef399b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt @@ -22,9 +22,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN -import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.R.string.keyguard_enter_pin import com.android.systemui.R.string.kg_too_many_failed_attempts_countdown +import com.android.systemui.R.string.kg_unlock_with_pin_or_fp import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.factory.BouncerMessageFactory import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository @@ -34,11 +33,11 @@ import com.android.systemui.coroutines.FlowValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.KotlinArgumentCaptor import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before @@ -49,14 +48,13 @@ import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations -@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @RunWith(AndroidJUnit4::class) class BouncerMessageInteractorTest : SysuiTestCase() { @Mock private lateinit var securityModel: KeyguardSecurityModel - @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor + @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository @Mock private lateinit var countDownTimerUtil: CountDownTimerUtil private lateinit var countDownTimerCallback: KotlinArgumentCaptor private lateinit var underTest: BouncerMessageInteractor @@ -73,10 +71,11 @@ class BouncerMessageInteractorTest : SysuiTestCase() { userRepository.setUserInfos(listOf(PRIMARY_USER)) testScope = TestScope() countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java) + biometricSettingsRepository = FakeBiometricSettingsRepository() allowTestableLooperAsMainThread() whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN) - whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false) + biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true) } suspend fun TestScope.init() { @@ -86,7 +85,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() { underTest = BouncerMessageInteractor( repository = repository, - factory = BouncerMessageFactory(updateMonitor, securityModel), + factory = BouncerMessageFactory(biometricSettingsRepository, securityModel), userRepository = userRepository, countDownTimerUtil = countDownTimerUtil, featureFlags = featureFlags @@ -151,7 +150,8 @@ class BouncerMessageInteractorTest : SysuiTestCase() { underTest.setCustomMessage("not empty") val customMessage = repository.customMessage - assertThat(customMessage.value!!.message!!.messageResId).isEqualTo(keyguard_enter_pin) + assertThat(customMessage.value!!.message!!.messageResId) + .isEqualTo(kg_unlock_with_pin_or_fp) assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty") underTest.setCustomMessage(null) @@ -168,7 +168,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() { val faceAcquisitionMessage = repository.faceAcquisitionMessage assertThat(faceAcquisitionMessage.value!!.message!!.messageResId) - .isEqualTo(keyguard_enter_pin) + .isEqualTo(kg_unlock_with_pin_or_fp) assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message) .isEqualTo("not empty") @@ -186,7 +186,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() { val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId) - .isEqualTo(keyguard_enter_pin) + .isEqualTo(kg_unlock_with_pin_or_fp) assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message) .isEqualTo("not empty") @@ -275,7 +275,8 @@ class BouncerMessageInteractorTest : SysuiTestCase() { repository.setBiometricLockedOutMessage(null) // sets the default message if everything else is null - assertThat(bouncerMessage()!!.message!!.messageResId).isEqualTo(keyguard_enter_pin) + assertThat(bouncerMessage()!!.message!!.messageResId) + .isEqualTo(kg_unlock_with_pin_or_fp) } private fun message(value: String): BouncerMessageModel { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt index c6a2fa50b446d..a6930d5953264 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt @@ -36,6 +36,11 @@ import com.android.systemui.R import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthController +import com.android.systemui.biometrics.data.repository.FaceSensorInfo +import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.BiometricType.FACE @@ -63,6 +68,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.isNull import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.times import org.mockito.Mockito.verify @@ -89,6 +95,8 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { ArgumentCaptor private lateinit var userRepository: FakeUserRepository private lateinit var devicePostureRepository: FakeDevicePostureRepository + private lateinit var facePropertyRepository: FakeFacePropertyRepository + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository private lateinit var testDispatcher: TestDispatcher private lateinit var testScope: TestScope @@ -102,6 +110,8 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { testScope = TestScope(testDispatcher) userRepository = FakeUserRepository() devicePostureRepository = FakeDevicePostureRepository() + facePropertyRepository = FakeFacePropertyRepository() + fingerprintPropertyRepository = FakeFingerprintPropertyRepository() } private suspend fun createBiometricSettingsRepository() { @@ -120,74 +130,110 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { biometricManager = biometricManager, devicePostureRepository = devicePostureRepository, dumpManager = dumpManager, + facePropertyRepository = facePropertyRepository, + fingerprintPropertyRepository = fingerprintPropertyRepository, ) testScope.runCurrent() + fingerprintPropertyRepository.setProperties( + 1, + SensorStrength.STRONG, + FingerprintSensorType.UDFPS_OPTICAL, + emptyMap() + ) verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture()) + verify(authController, atLeastOnce()).addCallback(authControllerCallback.capture()) } @Test fun fingerprintEnrollmentChange() = testScope.runTest { createBiometricSettingsRepository() - val fingerprintEnrolled = collectLastValue(underTest.isFingerprintEnrolled) + val fingerprintAllowed = collectLastValue(underTest.isFingerprintEnrolledAndEnabled) runCurrent() - verify(authController).addCallback(authControllerCallback.capture()) whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true) enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true) - assertThat(fingerprintEnrolled()).isTrue() + assertThat(fingerprintAllowed()).isTrue() whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(false) enrollmentChange(UNDER_DISPLAY_FINGERPRINT, ANOTHER_USER_ID, false) - assertThat(fingerprintEnrolled()).isTrue() + assertThat(fingerprintAllowed()).isTrue() enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, false) - assertThat(fingerprintEnrolled()).isFalse() + assertThat(fingerprintAllowed()).isFalse() } @Test fun strongBiometricAllowedChange() = testScope.runTest { + fingerprintIsEnrolled() + doNotDisableKeyguardAuthFeatures() createBiometricSettingsRepository() - val strongBiometricAllowed = collectLastValue(underTest.isStrongBiometricAllowed) + + val strongBiometricAllowed by + collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed) runCurrent() onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) - assertThat(strongBiometricAllowed()).isTrue() + assertThat(strongBiometricAllowed).isTrue() onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_BOOT, PRIMARY_USER_ID) - assertThat(strongBiometricAllowed()).isFalse() + assertThat(strongBiometricAllowed).isFalse() } @Test fun convenienceBiometricAllowedChange() = testScope.runTest { overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false) + deviceIsInPostureThatSupportsFaceAuth() + faceAuthIsEnrolled() + faceAuthIsNonStrongBiometric() createBiometricSettingsRepository() - val convenienceBiometricAllowed = - collectLastValue(underTest.isNonStrongBiometricAllowed) - runCurrent() + val convenienceFaceAuthAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed) + doNotDisableKeyguardAuthFeatures() + faceAuthIsEnabledByBiometricManager() + + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) onNonStrongAuthChanged(true, PRIMARY_USER_ID) - assertThat(convenienceBiometricAllowed()).isTrue() + runCurrent() + assertThat(convenienceFaceAuthAllowed).isTrue() onNonStrongAuthChanged(false, ANOTHER_USER_ID) - assertThat(convenienceBiometricAllowed()).isTrue() + assertThat(convenienceFaceAuthAllowed).isTrue() onNonStrongAuthChanged(false, PRIMARY_USER_ID) - assertThat(convenienceBiometricAllowed()).isFalse() + assertThat(convenienceFaceAuthAllowed).isFalse() mContext.orCreateTestableResources.removeOverride( com.android.internal.R.bool.config_strongAuthRequiredOnBoot ) } + private fun faceAuthIsNonStrongBiometric() { + facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.CONVENIENCE)) + } + + private fun faceAuthIsStrongBiometric() { + facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG)) + } + + private fun deviceIsInPostureThatSupportsFaceAuth() { + overrideResource( + R.integer.config_face_auth_supported_posture, + DevicePostureController.DEVICE_POSTURE_FLIPPED + ) + devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED) + } + @Test fun whenStrongAuthRequiredAfterBoot_nonStrongBiometricNotAllowed() = testScope.runTest { overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, true) createBiometricSettingsRepository() + faceAuthIsNonStrongBiometric() + faceAuthIsEnrolled() + doNotDisableKeyguardAuthFeatures() - val convenienceBiometricAllowed = - collectLastValue(underTest.isNonStrongBiometricAllowed) + val convenienceBiometricAllowed = collectLastValue(underTest.isFaceAuthCurrentlyAllowed) runCurrent() onNonStrongAuthChanged(true, PRIMARY_USER_ID) @@ -201,16 +247,24 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { fun whenStrongBiometricAuthIsNotAllowed_nonStrongBiometrics_alsoNotAllowed() = testScope.runTest { overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false) + faceAuthIsNonStrongBiometric() + deviceIsInPostureThatSupportsFaceAuth() + faceAuthIsEnrolled() createBiometricSettingsRepository() - - val convenienceBiometricAllowed = - collectLastValue(underTest.isNonStrongBiometricAllowed) + doNotDisableKeyguardAuthFeatures() + faceAuthIsEnabledByBiometricManager() runCurrent() + + val convenienceBiometricAllowed by + collectLastValue(underTest.isFaceAuthCurrentlyAllowed) + + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) onNonStrongAuthChanged(true, PRIMARY_USER_ID) - assertThat(convenienceBiometricAllowed()).isTrue() + runCurrent() + assertThat(convenienceBiometricAllowed).isTrue() onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, PRIMARY_USER_ID) - assertThat(convenienceBiometricAllowed()).isFalse() + assertThat(convenienceBiometricAllowed).isFalse() mContext.orCreateTestableResources.removeOverride( com.android.internal.R.bool.config_strongAuthRequiredOnBoot ) @@ -229,9 +283,11 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { @Test fun fingerprintDisabledByDpmChange() = testScope.runTest { + fingerprintIsEnrolled(PRIMARY_USER_ID) createBiometricSettingsRepository() + val fingerprintEnabledByDevicePolicy = - collectLastValue(underTest.isFingerprintEnabledByDevicePolicy) + collectLastValue(underTest.isFingerprintEnrolledAndEnabled) runCurrent() whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt())) @@ -244,43 +300,57 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { assertThat(fingerprintEnabledByDevicePolicy()).isTrue() } + private fun fingerprintIsEnrolled(userId: Int = PRIMARY_USER_ID) { + whenever(authController.isFingerprintEnrolled(userId)).thenReturn(true) + } + @Test fun faceEnrollmentChangeIsPropagatedForTheCurrentUser() = testScope.runTest { createBiometricSettingsRepository() + faceAuthIsEnabledByBiometricManager() + + doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID) + runCurrent() clearInvocations(authController) whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false) - val faceEnrolled = collectLastValue(underTest.isFaceEnrolled) + val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled) - assertThat(faceEnrolled()).isFalse() + assertThat(faceAuthAllowed()).isFalse() verify(authController).addCallback(authControllerCallback.capture()) enrollmentChange(REAR_FINGERPRINT, PRIMARY_USER_ID, true) - assertThat(faceEnrolled()).isFalse() + assertThat(faceAuthAllowed()).isFalse() enrollmentChange(SIDE_FINGERPRINT, PRIMARY_USER_ID, true) - assertThat(faceEnrolled()).isFalse() + assertThat(faceAuthAllowed()).isFalse() enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true) - assertThat(faceEnrolled()).isFalse() + assertThat(faceAuthAllowed()).isFalse() whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true) enrollmentChange(FACE, ANOTHER_USER_ID, true) - assertThat(faceEnrolled()).isFalse() + assertThat(faceAuthAllowed()).isFalse() - whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(true) + faceAuthIsEnrolled() enrollmentChange(FACE, PRIMARY_USER_ID, true) - assertThat(faceEnrolled()).isTrue() + assertThat(faceAuthAllowed()).isTrue() } + private fun faceAuthIsEnabledByBiometricManager(userId: Int = PRIMARY_USER_ID) { + verify(biometricManager, atLeastOnce()) + .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture()) + biometricManagerCallback.value.onChanged(true, userId) + } + @Test fun faceEnrollmentStatusOfNewUserUponUserSwitch() = testScope.runTest { @@ -290,21 +360,26 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false) whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true) - val faceEnrolled = collectLastValue(underTest.isFaceEnrolled) + val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled) - assertThat(faceEnrolled()).isFalse() + assertThat(faceAuthAllowed()).isFalse() } @Test fun faceEnrollmentChangesArePropagatedAfterUserSwitch() = testScope.runTest { createBiometricSettingsRepository() + verify(biometricManager) + .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture()) userRepository.setSelectedUserInfo(ANOTHER_USER) + doNotDisableKeyguardAuthFeatures(ANOTHER_USER_ID) + biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID) + runCurrent() clearInvocations(authController) - val faceEnrolled = collectLastValue(underTest.isFaceEnrolled) + val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled) runCurrent() verify(authController).addCallback(authControllerCallback.capture()) @@ -312,12 +387,14 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true) enrollmentChange(FACE, ANOTHER_USER_ID, true) - assertThat(faceEnrolled()).isTrue() + assertThat(faceAuthAllowed()).isTrue() } @Test fun devicePolicyControlsFaceAuthenticationEnabledState() = testScope.runTest { + faceAuthIsEnrolled() + createBiometricSettingsRepository() verify(biometricManager) .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture()) @@ -325,62 +402,70 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID))) .thenReturn(KEYGUARD_DISABLE_FINGERPRINT or KEYGUARD_DISABLE_FACE) - val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled) + val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled) runCurrent() broadcastDPMStateChange() - assertThat(isFaceAuthEnabled()).isFalse() + assertThat(isFaceAuthAllowed()).isFalse() biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID) runCurrent() - assertThat(isFaceAuthEnabled()).isFalse() + assertThat(isFaceAuthAllowed()).isFalse() whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID))) .thenReturn(KEYGUARD_DISABLE_FINGERPRINT) broadcastDPMStateChange() - assertThat(isFaceAuthEnabled()).isTrue() + assertThat(isFaceAuthAllowed()).isTrue() } @Test fun biometricManagerControlsFaceAuthenticationEnabledStatus() = testScope.runTest { + faceAuthIsEnrolled() + createBiometricSettingsRepository() verify(biometricManager) .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture()) whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID))) .thenReturn(0) broadcastDPMStateChange() - val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled) + val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled) - assertThat(isFaceAuthEnabled()).isFalse() + assertThat(isFaceAuthAllowed()).isFalse() // Value changes for another user biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID) - assertThat(isFaceAuthEnabled()).isFalse() + assertThat(isFaceAuthAllowed()).isFalse() // Value changes for current user. biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID) - assertThat(isFaceAuthEnabled()).isTrue() + assertThat(isFaceAuthAllowed()).isTrue() } + private fun faceAuthIsEnrolled(userId: Int = PRIMARY_USER_ID) { + whenever(authController.isFaceAuthEnrolled(userId)).thenReturn(true) + } + @Test fun userChange_biometricEnabledChange_handlesRaceCondition() = testScope.runTest { createBiometricSettingsRepository() + whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true) + verify(biometricManager) .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture()) - val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled) + val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled) biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID) runCurrent() userRepository.setSelectedUserInfo(ANOTHER_USER) runCurrent() - assertThat(isFaceAuthEnabled()).isTrue() + assertThat(isFaceAuthAllowed()).isTrue() } @Test @@ -388,9 +473,9 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { testScope.runTest { createBiometricSettingsRepository() - collectLastValue(underTest.isFaceAuthenticationEnabled)() - collectLastValue(underTest.isFaceAuthenticationEnabled)() - collectLastValue(underTest.isFaceAuthenticationEnabled)() + collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)() + collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)() + collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)() verify(biometricManager, times(1)).registerEnabledOnKeyguardCallback(any()) } @@ -495,10 +580,138 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { assertThat(authFlags()!!.flag).isEqualTo(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) } + @Test + fun faceAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFaceIsClass3() = + testScope.runTest { + createBiometricSettingsRepository() + val isFaceAuthCurrentlyAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed) + + faceAuthIsEnrolled() + deviceIsInPostureThatSupportsFaceAuth() + doNotDisableKeyguardAuthFeatures() + faceAuthIsStrongBiometric() + faceAuthIsEnabledByBiometricManager() + + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) + onNonStrongAuthChanged(false, PRIMARY_USER_ID) + + assertThat(isFaceAuthCurrentlyAllowed).isTrue() + + onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID) + onNonStrongAuthChanged(true, PRIMARY_USER_ID) + + assertThat(isFaceAuthCurrentlyAllowed).isFalse() + } + + @Test + fun faceAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFaceIsNotStrong() = + testScope.runTest { + createBiometricSettingsRepository() + val isFaceAuthCurrentlyAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed) + + faceAuthIsEnrolled() + deviceIsInPostureThatSupportsFaceAuth() + doNotDisableKeyguardAuthFeatures() + faceAuthIsNonStrongBiometric() + faceAuthIsEnabledByBiometricManager() + + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) + onNonStrongAuthChanged(false, PRIMARY_USER_ID) + + assertThat(isFaceAuthCurrentlyAllowed).isFalse() + + onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID) + onNonStrongAuthChanged(true, PRIMARY_USER_ID) + + assertThat(isFaceAuthCurrentlyAllowed).isFalse() + + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) + onNonStrongAuthChanged(true, PRIMARY_USER_ID) + + assertThat(isFaceAuthCurrentlyAllowed).isTrue() + } + + @Test + fun fpAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFpIsNotStrong() = + testScope.runTest { + createBiometricSettingsRepository() + val isFingerprintCurrentlyAllowed by + collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed) + + fingerprintIsEnrolled(PRIMARY_USER_ID) + enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true) + doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID) + runCurrent() + + fingerprintPropertyRepository.setProperties( + 1, + SensorStrength.STRONG, + FingerprintSensorType.UDFPS_OPTICAL, + emptyMap() + ) + // Non strong auth is not allowed now, FP is marked strong + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) + onNonStrongAuthChanged(false, PRIMARY_USER_ID) + + assertThat(isFingerprintCurrentlyAllowed).isTrue() + + fingerprintPropertyRepository.setProperties( + 1, + SensorStrength.CONVENIENCE, + FingerprintSensorType.UDFPS_OPTICAL, + emptyMap() + ) + assertThat(isFingerprintCurrentlyAllowed).isFalse() + + fingerprintPropertyRepository.setProperties( + 1, + SensorStrength.WEAK, + FingerprintSensorType.UDFPS_OPTICAL, + emptyMap() + ) + assertThat(isFingerprintCurrentlyAllowed).isFalse() + } + + @Test + fun fpAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFpIsStrong() = + testScope.runTest { + createBiometricSettingsRepository() + val isFingerprintCurrentlyAllowed by + collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed) + + fingerprintIsEnrolled(PRIMARY_USER_ID) + enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true) + doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID) + runCurrent() + + fingerprintPropertyRepository.setProperties( + 1, + SensorStrength.STRONG, + FingerprintSensorType.UDFPS_OPTICAL, + emptyMap() + ) + // Non strong auth is not allowed now, FP is marked strong + onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID) + onNonStrongAuthChanged(true, PRIMARY_USER_ID) + + assertThat(isFingerprintCurrentlyAllowed).isFalse() + + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) + onNonStrongAuthChanged(false, PRIMARY_USER_ID) + + assertThat(isFingerprintCurrentlyAllowed).isTrue() + } + private fun enrollmentChange(biometricType: BiometricType, userId: Int, enabled: Boolean) { authControllerCallback.value.onEnrollmentsChanged(biometricType, userId, enabled) } + private fun doNotDisableKeyguardAuthFeatures(userId: Int = PRIMARY_USER_ID) { + whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(userId))) + .thenReturn(0) + broadcastDPMStateChange() + } + private fun broadcastDPMStateChange() { fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index fe5b8120428d4..64b94707da571 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -40,9 +40,7 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FaceSensorInfo import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository -import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.coroutines.FlowValue @@ -255,7 +253,6 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { faceAuthBuffer, keyguardTransitionInteractor, featureFlags, - fakeFacePropertyRepository, dumpManager, ) } @@ -525,15 +522,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test - fun authenticateDoesNotRunIfFaceIsNotEnrolled() = + fun authenticateDoesNotRunIfFaceIsNotUsuallyAllowed() = testScope.runTest { - testGatingCheckForFaceAuth { biometricSettingsRepository.setFaceEnrolled(false) } - } - - @Test - fun authenticateDoesNotRunIfFaceIsNotEnabled() = - testScope.runTest { - testGatingCheckForFaceAuth { biometricSettingsRepository.setIsFaceAuthEnabled(false) } + testGatingCheckForFaceAuth { + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false) + } } @Test @@ -589,21 +582,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test - fun authenticateDoesNotRunWhenNonStrongBiometricIsNotAllowed() = + fun authenticateDoesNotRunWhenFaceAuthIsNotCurrentlyAllowedToRun() = testScope.runTest { testGatingCheckForFaceAuth { - biometricSettingsRepository.setIsNonStrongBiometricAllowed(false) - } - } - - @Test - fun authenticateDoesNotRunWhenStrongBiometricIsNotAllowedAndFaceSensorIsStrong() = - testScope.runTest { - fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG)) - runCurrent() - - testGatingCheckForFaceAuth(isFaceStrong = true) { - biometricSettingsRepository.setIsStrongBiometricAllowed(false) + biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false) } } @@ -662,7 +644,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { allPreconditionsToRunFaceAuthAreTrue() // Flip one precondition to false. - biometricSettingsRepository.setIsNonStrongBiometricAllowed(false) + biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false) assertThat(canFaceAuthRun()).isFalse() underTest.authenticate( FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER, @@ -827,15 +809,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test - fun detectDoesNotRunWhenFaceIsNotEnrolled() = + fun detectDoesNotRunWhenFaceIsNotUsuallyAllowed() = testScope.runTest { - testGatingCheckForDetect { biometricSettingsRepository.setFaceEnrolled(false) } - } - - @Test - fun detectDoesNotRunWhenFaceIsNotEnabled() = - testScope.runTest { - testGatingCheckForDetect { biometricSettingsRepository.setIsFaceAuthEnabled(false) } + testGatingCheckForDetect { + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false) + } } @Test @@ -932,23 +910,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test - fun detectDoesNotRunWhenNonStrongBiometricIsAllowed() = + fun detectDoesNotRunWhenFaceAuthIsCurrentlyAllowedToRun() = testScope.runTest { testGatingCheckForDetect { - biometricSettingsRepository.setIsNonStrongBiometricAllowed(true) - } - } - - @Test - fun detectDoesNotRunWhenStrongBiometricIsAllowedAndFaceAuthSensorStrengthIsStrong() = - testScope.runTest { - fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG)) - runCurrent() - - testGatingCheckForDetect(isFaceStrong = true) { - biometricSettingsRepository.setIsStrongBiometricAllowed(true) - // this shouldn't matter as face is set as a strong sensor - biometricSettingsRepository.setIsNonStrongBiometricAllowed(false) + biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true) } } @@ -1043,12 +1008,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { faceAuthenticateIsCalled() } - private suspend fun TestScope.testGatingCheckForFaceAuth( - isFaceStrong: Boolean = false, - gatingCheckModifier: () -> Unit - ) { + private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) { initCollectors() - allPreconditionsToRunFaceAuthAreTrue(isFaceStrong) + allPreconditionsToRunFaceAuthAreTrue() gatingCheckModifier() runCurrent() @@ -1057,7 +1019,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { assertThat(underTest.canRunFaceAuth.value).isFalse() // flip the gating check back on. - allPreconditionsToRunFaceAuthAreTrue(isFaceStrong) + allPreconditionsToRunFaceAuthAreTrue() triggerFaceAuth(false) @@ -1076,19 +1038,12 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { faceAuthenticateIsNotCalled() } - private suspend fun TestScope.testGatingCheckForDetect( - isFaceStrong: Boolean = false, - gatingCheckModifier: () -> Unit - ) { + private suspend fun TestScope.testGatingCheckForDetect(gatingCheckModifier: () -> Unit) { initCollectors() allPreconditionsToRunFaceAuthAreTrue() - if (isFaceStrong) { - biometricSettingsRepository.setStrongBiometricAllowed(false) - } else { - // This will stop face auth from running but is required to be false for detect. - biometricSettingsRepository.setIsNonStrongBiometricAllowed(false) - } + // This will stop face auth from running but is required to be false for detect. + biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false) runCurrent() assertThat(canFaceAuthRun()).isFalse() @@ -1123,13 +1078,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { cancellationSignal.value.setOnCancelListener { wasAuthCancelled = true } } - private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue( - isFaceStrong: Boolean = false - ) { + private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() { verify(faceManager, atLeastOnce()) .addLockoutResetCallback(faceLockoutResetCallback.capture()) - biometricSettingsRepository.setFaceEnrolled(true) - biometricSettingsRepository.setIsFaceAuthEnabled(true) underTest.resumeFaceAuth() trustRepository.setCurrentUserTrusted(false) keyguardRepository.setKeyguardGoingAway(false) @@ -1140,14 +1091,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { WakeSleepReason.OTHER ) ) - if (isFaceStrong) { - biometricSettingsRepository.setStrongBiometricAllowed(true) - } else { - biometricSettingsRepository.setIsNonStrongBiometricAllowed(true) - } + biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true) + biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true) + biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true) biometricSettingsRepository.setIsUserInLockdown(false) fakeUserRepository.setSelectedUserInfo(primaryUser) - biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true) faceLockoutResetCallback.value.onLockoutReset(0) bouncerRepository.setAlternateVisible(true) keyguardRepository.setKeyguardShowing(true) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt index 8c98aea6a9900..e91e9559fa1e2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt @@ -22,32 +22,24 @@ import com.android.systemui.keyguard.shared.model.AuthenticationFlags import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.map class FakeBiometricSettingsRepository : BiometricSettingsRepository { + private val _isFingerprintEnrolledAndEnabled = MutableStateFlow(false) + override val isFingerprintEnrolledAndEnabled: StateFlow + get() = _isFingerprintEnrolledAndEnabled - private val _isFingerprintEnrolled = MutableStateFlow(false) - override val isFingerprintEnrolled: StateFlow = _isFingerprintEnrolled.asStateFlow() + private val _isFingerprintAuthCurrentlyAllowed = MutableStateFlow(false) + override val isFingerprintAuthCurrentlyAllowed: StateFlow + get() = _isFingerprintAuthCurrentlyAllowed - private val _isFaceEnrolled = MutableStateFlow(false) - override val isFaceEnrolled: Flow - get() = _isFaceEnrolled + private val _isFaceAuthEnrolledAndEnabled = MutableStateFlow(false) + override val isFaceAuthEnrolledAndEnabled: Flow + get() = _isFaceAuthEnrolledAndEnabled - private val _isFaceAuthEnabled = MutableStateFlow(false) - override val isFaceAuthenticationEnabled: Flow - get() = _isFaceAuthEnabled - - private val _isStrongBiometricAllowed = MutableStateFlow(false) - override val isStrongBiometricAllowed = _isStrongBiometricAllowed.asStateFlow() - - private val _isNonStrongBiometricAllowed = MutableStateFlow(false) - override val isNonStrongBiometricAllowed: StateFlow - get() = _isNonStrongBiometricAllowed - - private val _isFingerprintEnabledByDevicePolicy = MutableStateFlow(false) - override val isFingerprintEnabledByDevicePolicy = - _isFingerprintEnabledByDevicePolicy.asStateFlow() + private val _isFaceAuthCurrentlyAllowed = MutableStateFlow(false) + override val isFaceAuthCurrentlyAllowed: Flow + get() = _isFaceAuthCurrentlyAllowed private val _isFaceAuthSupportedInCurrentPosture = MutableStateFlow(false) override val isFaceAuthSupportedInCurrentPosture: Flow @@ -59,34 +51,33 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository { private val _authFlags = MutableStateFlow(AuthenticationFlags(0, 0)) override val authenticationFlags: Flow get() = _authFlags - fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) { - _isFingerprintEnrolled.value = isFingerprintEnrolled - } - - fun setStrongBiometricAllowed(isStrongBiometricAllowed: Boolean) { - _isStrongBiometricAllowed.value = isStrongBiometricAllowed - } - - fun setFingerprintEnabledByDevicePolicy(isFingerprintEnabledByDevicePolicy: Boolean) { - _isFingerprintEnabledByDevicePolicy.value = isFingerprintEnabledByDevicePolicy - } fun setAuthenticationFlags(value: AuthenticationFlags) { _authFlags.value = value } - fun setFaceEnrolled(isFaceEnrolled: Boolean) { - _isFaceEnrolled.value = isFaceEnrolled + fun setIsFingerprintAuthEnrolledAndEnabled(value: Boolean) { + _isFingerprintEnrolledAndEnabled.value = value + _isFingerprintAuthCurrentlyAllowed.value = _isFingerprintAuthCurrentlyAllowed.value && value + } + + fun setIsFingerprintAuthCurrentlyAllowed(value: Boolean) { + _isFingerprintAuthCurrentlyAllowed.value = value + } + + fun setIsFaceAuthEnrolledAndEnabled(value: Boolean) { + _isFaceAuthEnrolledAndEnabled.value = value + _isFaceAuthCurrentlyAllowed.value = _isFaceAuthCurrentlyAllowed.value && value + } + + fun setIsFaceAuthCurrentlyAllowed(value: Boolean) { + _isFaceAuthCurrentlyAllowed.value = value } fun setIsFaceAuthSupportedInCurrentPosture(value: Boolean) { _isFaceAuthSupportedInCurrentPosture.value = value } - fun setIsFaceAuthEnabled(enabled: Boolean) { - _isFaceAuthEnabled.value = enabled - } - fun setIsUserInLockdown(value: Boolean) { if (value) { setAuthenticationFlags( @@ -105,12 +96,4 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository { ) } } - - fun setIsNonStrongBiometricAllowed(value: Boolean) { - _isNonStrongBiometricAllowed.value = value - } - - fun setIsStrongBiometricAllowed(value: Boolean) { - _isStrongBiometricAllowed.value = value - } }