Merge "Add face auth enrollment state to BiometricSettingsRepository" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2023-02-07 01:45:34 +00:00
committed by Android (Google) Code Review
3 changed files with 299 additions and 39 deletions

View File

@@ -20,6 +20,8 @@ import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED import android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
import android.content.Context import android.content.Context
import android.content.IntentFilter import android.content.IntentFilter
import android.hardware.biometrics.BiometricManager
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback
import android.os.Looper import android.os.Looper
import android.os.UserHandle import android.os.UserHandle
import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternUtils
@@ -42,10 +44,12 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
@@ -60,6 +64,15 @@ interface BiometricSettingsRepository {
/** Whether any fingerprints are enrolled for the current user. */ /** Whether any fingerprints are enrolled for the current user. */
val isFingerprintEnrolled: StateFlow<Boolean> val isFingerprintEnrolled: StateFlow<Boolean>
/** Whether face authentication is enrolled for the current user. */
val isFaceEnrolled: Flow<Boolean>
/**
* Whether face authentication is enabled/disabled based on system settings like device policy,
* biometrics setting.
*/
val isFaceAuthenticationEnabled: Flow<Boolean>
/** /**
* Whether the current user is allowed to use a strong biometric for device entry based on * 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 * Android Security policies. If false, the user may be able to use primary authentication for
@@ -83,6 +96,7 @@ constructor(
devicePolicyManager: DevicePolicyManager, devicePolicyManager: DevicePolicyManager,
@Application scope: CoroutineScope, @Application scope: CoroutineScope,
@Background backgroundDispatcher: CoroutineDispatcher, @Background backgroundDispatcher: CoroutineDispatcher,
biometricManager: BiometricManager?,
@Main looper: Looper, @Main looper: Looper,
dumpManager: DumpManager, dumpManager: DumpManager,
) : BiometricSettingsRepository, Dumpable { ) : BiometricSettingsRepository, Dumpable {
@@ -101,9 +115,15 @@ constructor(
private val selectedUserId: Flow<Int> = private val selectedUserId: Flow<Int> =
userRepository.selectedUserInfo.map { it.id }.distinctUntilChanged() userRepository.selectedUserInfo.map { it.id }.distinctUntilChanged()
private val devicePolicyChangedForAllUsers =
broadcastDispatcher.broadcastFlow(
filter = IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
user = UserHandle.ALL
)
override val isFingerprintEnrolled: StateFlow<Boolean> = override val isFingerprintEnrolled: StateFlow<Boolean> =
selectedUserId selectedUserId
.flatMapLatest { .flatMapLatest { currentUserId ->
conflatedCallbackFlow { conflatedCallbackFlow {
val callback = val callback =
object : AuthController.Callback { object : AuthController.Callback {
@@ -112,7 +132,7 @@ constructor(
userId: Int, userId: Int,
hasEnrollments: Boolean hasEnrollments: Boolean
) { ) {
if (sensorBiometricType.isFingerprint) { if (sensorBiometricType.isFingerprint && userId == currentUserId) {
trySendWithFailureLogging( trySendWithFailureLogging(
hasEnrollments, hasEnrollments,
TAG, TAG,
@@ -132,6 +152,77 @@ constructor(
authController.isFingerprintEnrolled(userRepository.getSelectedUserInfo().id) authController.isFingerprintEnrolled(userRepository.getSelectedUserInfo().id)
) )
override val isFaceEnrolled: Flow<Boolean> =
selectedUserId.flatMapLatest { selectedUserId: Int ->
conflatedCallbackFlow {
val callback =
object : AuthController.Callback {
override fun onEnrollmentsChanged(
sensorBiometricType: BiometricType,
userId: Int,
hasEnrollments: Boolean
) {
// TODO(b/242022358), use authController.isFaceAuthEnrolled after
// ag/20176811 is available.
if (
sensorBiometricType == BiometricType.FACE &&
userId == selectedUserId
) {
trySendWithFailureLogging(
hasEnrollments,
TAG,
"Face enrollment changed"
)
}
}
}
authController.addCallback(callback)
trySendWithFailureLogging(
authController.isFaceAuthEnrolled(selectedUserId),
TAG,
"Initial value of face auth enrollment"
)
awaitClose { authController.removeCallback(callback) }
}
}
override val isFaceAuthenticationEnabled: Flow<Boolean>
get() =
combine(isFaceEnabledByBiometricsManager, isFaceEnabledByDevicePolicy) {
biometricsManagerSetting,
devicePolicySetting ->
biometricsManagerSetting && devicePolicySetting
}
private val isFaceEnabledByDevicePolicy: Flow<Boolean> =
combine(selectedUserId, devicePolicyChangedForAllUsers) { userId, _ ->
devicePolicyManager.isFaceDisabled(userId)
}
.onStart {
emit(devicePolicyManager.isFaceDisabled(userRepository.getSelectedUserInfo().id))
}
.flowOn(backgroundDispatcher)
.distinctUntilChanged()
private val isFaceEnabledByBiometricsManager =
conflatedCallbackFlow {
val callback =
object : IBiometricEnabledOnKeyguardCallback.Stub() {
override fun onChanged(enabled: Boolean, userId: Int) {
trySendWithFailureLogging(
enabled,
TAG,
"biometricsEnabled state changed"
)
}
}
biometricManager?.registerEnabledOnKeyguardCallback(callback)
awaitClose {}
}
// This is because the callback is binder-based and we want to avoid multiple callbacks
// being registered.
.stateIn(scope, SharingStarted.Eagerly, false)
override val isStrongBiometricAllowed: StateFlow<Boolean> = override val isStrongBiometricAllowed: StateFlow<Boolean> =
selectedUserId selectedUserId
.flatMapLatest { currUserId -> .flatMapLatest { currUserId ->
@@ -169,17 +260,8 @@ constructor(
override val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> = override val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> =
selectedUserId selectedUserId
.flatMapLatest { userId -> .flatMapLatest { userId ->
broadcastDispatcher devicePolicyChangedForAllUsers
.broadcastFlow( .transformLatest { emit(devicePolicyManager.isFingerprintDisabled(userId)) }
filter = IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
user = UserHandle.ALL
)
.transformLatest {
emit(
(devicePolicyManager.getKeyguardDisabledFeatures(null, userId) and
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) == 0
)
}
.flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher)
.distinctUntilChanged() .distinctUntilChanged()
} }
@@ -187,13 +269,21 @@ constructor(
scope, scope,
started = SharingStarted.Eagerly, started = SharingStarted.Eagerly,
initialValue = initialValue =
devicePolicyManager.getKeyguardDisabledFeatures( devicePolicyManager.isFingerprintDisabled(
null,
userRepository.getSelectedUserInfo().id userRepository.getSelectedUserInfo().id
) and DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT == 0 )
) )
companion object { companion object {
private const val TAG = "BiometricsRepositoryImpl" private const val TAG = "BiometricsRepositoryImpl"
} }
} }
private fun DevicePolicyManager.isFaceDisabled(userId: Int): Boolean =
isNotActive(userId, DevicePolicyManager.KEYGUARD_DISABLE_FACE)
private fun DevicePolicyManager.isFingerprintDisabled(userId: Int): Boolean =
isNotActive(userId, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT)
private fun DevicePolicyManager.isNotActive(userId: Int, policy: Int): Boolean =
(getKeyguardDisabledFeatures(null, userId) and policy) == 0

View File

@@ -18,8 +18,12 @@
package com.android.systemui.keyguard.data.repository package com.android.systemui.keyguard.data.repository
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT
import android.content.Intent import android.content.Intent
import android.content.pm.UserInfo import android.content.pm.UserInfo
import android.hardware.biometrics.BiometricManager
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -30,8 +34,13 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.AuthController
import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.BiometricType.FACE
import com.android.systemui.keyguard.data.repository.BiometricType.REAR_FINGERPRINT
import com.android.systemui.keyguard.data.repository.BiometricType.SIDE_FINGERPRINT
import com.android.systemui.keyguard.data.repository.BiometricType.UNDER_DISPLAY_FINGERPRINT
import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
@@ -42,9 +51,14 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.isNull
import org.mockito.Captor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -58,6 +72,11 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
@Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var lockPatternUtils: LockPatternUtils
@Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var biometricManager: BiometricManager
@Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback>
@Captor
private lateinit var biometricManagerCallback:
ArgumentCaptor<IBiometricEnabledOnKeyguardCallback.Stub>
private lateinit var userRepository: FakeUserRepository private lateinit var userRepository: FakeUserRepository
private lateinit var testDispatcher: TestDispatcher private lateinit var testDispatcher: TestDispatcher
@@ -74,7 +93,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
} }
private suspend fun createBiometricSettingsRepository() { private suspend fun createBiometricSettingsRepository() {
userRepository.setUserInfos(listOf(PRIMARY_USER)) userRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER))
userRepository.setSelectedUserInfo(PRIMARY_USER) userRepository.setSelectedUserInfo(PRIMARY_USER)
underTest = underTest =
BiometricSettingsRepositoryImpl( BiometricSettingsRepositoryImpl(
@@ -88,33 +107,29 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
backgroundDispatcher = testDispatcher, backgroundDispatcher = testDispatcher,
looper = testableLooper!!.looper, looper = testableLooper!!.looper,
dumpManager = dumpManager, dumpManager = dumpManager,
biometricManager = biometricManager,
) )
testScope.runCurrent()
} }
@Test @Test
fun fingerprintEnrollmentChange() = fun fingerprintEnrollmentChange() =
testScope.runTest { testScope.runTest {
createBiometricSettingsRepository() createBiometricSettingsRepository()
val fingerprintEnabledByDevicePolicy = collectLastValue(underTest.isFingerprintEnrolled) val fingerprintEnrolled = collectLastValue(underTest.isFingerprintEnrolled)
runCurrent() runCurrent()
val captor = argumentCaptor<AuthController.Callback>() verify(authController).addCallback(authControllerCallback.capture())
verify(authController).addCallback(captor.capture())
whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true) whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true)
captor.value.onEnrollmentsChanged( enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
BiometricType.UNDER_DISPLAY_FINGERPRINT, assertThat(fingerprintEnrolled()).isTrue()
PRIMARY_USER_ID,
true
)
assertThat(fingerprintEnabledByDevicePolicy()).isTrue()
whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(false) whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(false)
captor.value.onEnrollmentsChanged( enrollmentChange(UNDER_DISPLAY_FINGERPRINT, ANOTHER_USER_ID, false)
BiometricType.UNDER_DISPLAY_FINGERPRINT, assertThat(fingerprintEnrolled()).isTrue()
PRIMARY_USER_ID,
false enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, false)
) assertThat(fingerprintEnrolled()).isFalse()
assertThat(fingerprintEnabledByDevicePolicy()).isFalse()
} }
@Test @Test
@@ -127,15 +142,14 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
val captor = argumentCaptor<LockPatternUtils.StrongAuthTracker>() val captor = argumentCaptor<LockPatternUtils.StrongAuthTracker>()
verify(lockPatternUtils).registerStrongAuthTracker(captor.capture()) verify(lockPatternUtils).registerStrongAuthTracker(captor.capture())
captor.value captor.value.stub.onStrongAuthRequiredChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
.getStub()
.onStrongAuthRequiredChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper
assertThat(strongBiometricAllowed()).isTrue() assertThat(strongBiometricAllowed()).isTrue()
captor.value captor.value.stub.onStrongAuthRequiredChanged(
.getStub() STRONG_AUTH_REQUIRED_AFTER_BOOT,
.onStrongAuthRequiredChanged(STRONG_AUTH_REQUIRED_AFTER_BOOT, PRIMARY_USER_ID) PRIMARY_USER_ID
)
testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper
assertThat(strongBiometricAllowed()).isFalse() assertThat(strongBiometricAllowed()).isFalse()
} }
@@ -149,7 +163,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
runCurrent() runCurrent()
whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt())) whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) .thenReturn(KEYGUARD_DISABLE_FINGERPRINT)
broadcastDPMStateChange() broadcastDPMStateChange()
assertThat(fingerprintEnabledByDevicePolicy()).isFalse() assertThat(fingerprintEnabledByDevicePolicy()).isFalse()
@@ -158,6 +172,137 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
assertThat(fingerprintEnabledByDevicePolicy()).isTrue() assertThat(fingerprintEnabledByDevicePolicy()).isTrue()
} }
@Test
fun faceEnrollmentChangeIsPropagatedForTheCurrentUser() =
testScope.runTest {
createBiometricSettingsRepository()
runCurrent()
clearInvocations(authController)
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false)
val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
assertThat(faceEnrolled()).isFalse()
verify(authController).addCallback(authControllerCallback.capture())
enrollmentChange(REAR_FINGERPRINT, PRIMARY_USER_ID, true)
assertThat(faceEnrolled()).isFalse()
enrollmentChange(SIDE_FINGERPRINT, PRIMARY_USER_ID, true)
assertThat(faceEnrolled()).isFalse()
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
assertThat(faceEnrolled()).isFalse()
enrollmentChange(FACE, ANOTHER_USER_ID, true)
assertThat(faceEnrolled()).isFalse()
enrollmentChange(FACE, PRIMARY_USER_ID, true)
assertThat(faceEnrolled()).isTrue()
}
@Test
fun faceEnrollmentStatusOfNewUserUponUserSwitch() =
testScope.runTest {
createBiometricSettingsRepository()
runCurrent()
clearInvocations(authController)
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false)
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
assertThat(faceEnrolled()).isFalse()
}
@Test
fun faceEnrollmentChangesArePropagatedAfterUserSwitch() =
testScope.runTest {
createBiometricSettingsRepository()
userRepository.setSelectedUserInfo(ANOTHER_USER)
runCurrent()
clearInvocations(authController)
val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
runCurrent()
verify(authController).addCallback(authControllerCallback.capture())
enrollmentChange(FACE, ANOTHER_USER_ID, true)
assertThat(faceEnrolled()).isTrue()
}
@Test
fun devicePolicyControlsFaceAuthenticationEnabledState() =
testScope.runTest {
createBiometricSettingsRepository()
verify(biometricManager)
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT or KEYGUARD_DISABLE_FACE)
val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
runCurrent()
broadcastDPMStateChange()
assertThat(isFaceAuthEnabled()).isFalse()
biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID)
runCurrent()
assertThat(isFaceAuthEnabled()).isFalse()
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT)
broadcastDPMStateChange()
assertThat(isFaceAuthEnabled()).isTrue()
}
@Test
fun biometricManagerControlsFaceAuthenticationEnabledStatus() =
testScope.runTest {
createBiometricSettingsRepository()
verify(biometricManager)
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
.thenReturn(0)
broadcastDPMStateChange()
biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID)
val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
assertThat(isFaceAuthEnabled()).isTrue()
biometricManagerCallback.value.onChanged(false, PRIMARY_USER_ID)
assertThat(isFaceAuthEnabled()).isFalse()
}
@Test
fun biometricManagerCallbackIsRegisteredOnlyOnce() =
testScope.runTest {
createBiometricSettingsRepository()
collectLastValue(underTest.isFaceAuthenticationEnabled)()
collectLastValue(underTest.isFaceAuthenticationEnabled)()
collectLastValue(underTest.isFaceAuthenticationEnabled)()
verify(biometricManager, times(1)).registerEnabledOnKeyguardCallback(any())
}
private fun enrollmentChange(biometricType: BiometricType, userId: Int, enabled: Boolean) {
authControllerCallback.value.onEnrollmentsChanged(biometricType, userId, enabled)
}
private fun broadcastDPMStateChange() { private fun broadcastDPMStateChange() {
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver -> fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive( receiver.onReceive(
@@ -175,5 +320,13 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
/* name= */ "primary user", /* name= */ "primary user",
/* flags= */ UserInfo.FLAG_PRIMARY /* flags= */ UserInfo.FLAG_PRIMARY
) )
private const val ANOTHER_USER_ID = 1
private val ANOTHER_USER =
UserInfo(
/* id= */ ANOTHER_USER_ID,
/* name= */ "another user",
/* flags= */ UserInfo.FLAG_PRIMARY
)
} }
} }

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.repository package com.android.systemui.keyguard.data.repository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -26,6 +27,14 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
private val _isFingerprintEnrolled = MutableStateFlow<Boolean>(false) private val _isFingerprintEnrolled = MutableStateFlow<Boolean>(false)
override val isFingerprintEnrolled: StateFlow<Boolean> = _isFingerprintEnrolled.asStateFlow() override val isFingerprintEnrolled: StateFlow<Boolean> = _isFingerprintEnrolled.asStateFlow()
private val _isFaceEnrolled = MutableStateFlow(false)
override val isFaceEnrolled: Flow<Boolean>
get() = _isFaceEnrolled
private val _isFaceAuthEnabled = MutableStateFlow(false)
override val isFaceAuthenticationEnabled: Flow<Boolean>
get() = _isFaceAuthEnabled
private val _isStrongBiometricAllowed = MutableStateFlow(false) private val _isStrongBiometricAllowed = MutableStateFlow(false)
override val isStrongBiometricAllowed = _isStrongBiometricAllowed.asStateFlow() override val isStrongBiometricAllowed = _isStrongBiometricAllowed.asStateFlow()
@@ -44,4 +53,12 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
fun setFingerprintEnabledByDevicePolicy(isFingerprintEnabledByDevicePolicy: Boolean) { fun setFingerprintEnabledByDevicePolicy(isFingerprintEnabledByDevicePolicy: Boolean) {
_isFingerprintEnabledByDevicePolicy.value = isFingerprintEnabledByDevicePolicy _isFingerprintEnabledByDevicePolicy.value = isFingerprintEnabledByDevicePolicy
} }
fun setFaceEnrolled(isFaceEnrolled: Boolean) {
_isFaceEnrolled.value = isFaceEnrolled
}
fun setIsFaceAuthEnabled(enabled: Boolean) {
_isFaceAuthEnabled.value = enabled
}
} }