Merge changes I1a0a4767,I261a3f3e into udc-qpr-dev
* changes: Support class 3 face auth Add FaceSensorRepository to provide the face sensor state when it becomes available.
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
package com.android.systemui.biometrics.dagger
|
||||
|
||||
import com.android.settingslib.udfps.UdfpsUtils
|
||||
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
|
||||
import com.android.systemui.biometrics.data.repository.FacePropertyRepositoryImpl
|
||||
import com.android.systemui.biometrics.data.repository.FaceSettingsRepository
|
||||
import com.android.systemui.biometrics.data.repository.FaceSettingsRepositoryImpl
|
||||
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
|
||||
@@ -51,6 +53,10 @@ interface BiometricsModule {
|
||||
@SysUISingleton
|
||||
fun faceSettings(impl: FaceSettingsRepositoryImpl): FaceSettingsRepository
|
||||
|
||||
@Binds
|
||||
@SysUISingleton
|
||||
fun faceSensors(impl: FacePropertyRepositoryImpl): FacePropertyRepository
|
||||
|
||||
@Binds
|
||||
@SysUISingleton
|
||||
fun biometricPromptRepository(impl: PromptRepositoryImpl): PromptRepository
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics.data.repository
|
||||
|
||||
import android.hardware.face.FaceManager
|
||||
import android.hardware.face.FaceSensorPropertiesInternal
|
||||
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.biometrics.shared.model.toSensorStrength
|
||||
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
||||
/** A repository for the global state of Face sensor. */
|
||||
interface FacePropertyRepository {
|
||||
/** Face sensor information, null if it is not available. */
|
||||
val sensorInfo: Flow<FaceSensorInfo?>
|
||||
}
|
||||
|
||||
/** Describes a biometric sensor */
|
||||
data class FaceSensorInfo(val id: Int, val strength: SensorStrength)
|
||||
|
||||
private const val TAG = "FaceSensorPropertyRepositoryImpl"
|
||||
|
||||
@SysUISingleton
|
||||
class FacePropertyRepositoryImpl
|
||||
@Inject
|
||||
constructor(@Application private val applicationScope: CoroutineScope, faceManager: FaceManager?) :
|
||||
FacePropertyRepository {
|
||||
|
||||
private val sensorProps: Flow<List<FaceSensorPropertiesInternal>> =
|
||||
faceManager?.let {
|
||||
ConflatedCallbackFlow.conflatedCallbackFlow {
|
||||
val callback =
|
||||
object : IFaceAuthenticatorsRegisteredCallback.Stub() {
|
||||
override fun onAllAuthenticatorsRegistered(
|
||||
sensors: List<FaceSensorPropertiesInternal>
|
||||
) {
|
||||
trySendWithFailureLogging(
|
||||
sensors,
|
||||
TAG,
|
||||
"onAllAuthenticatorsRegistered"
|
||||
)
|
||||
}
|
||||
}
|
||||
it.addAuthenticatorsRegisteredCallback(callback)
|
||||
awaitClose {}
|
||||
}
|
||||
.shareIn(applicationScope, SharingStarted.Eagerly)
|
||||
}
|
||||
?: flowOf(emptyList())
|
||||
|
||||
override val sensorInfo: Flow<FaceSensorInfo?> =
|
||||
sensorProps
|
||||
.map { it.firstOrNull() }
|
||||
.map { it?.let { FaceSensorInfo(it.sensorId, it.sensorStrength.toSensorStrength()) } }
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.biometrics.shared.model.toSensorStrength
|
||||
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
@@ -106,7 +107,7 @@ constructor(
|
||||
|
||||
private fun setProperties(prop: FingerprintSensorPropertiesInternal) {
|
||||
_sensorId.value = prop.sensorId
|
||||
_strength.value = sensorStrengthIntToObject(prop.sensorStrength)
|
||||
_strength.value = prop.sensorStrength.toSensorStrength()
|
||||
_sensorType.value = sensorTypeIntToObject(prop.sensorType)
|
||||
_sensorLocations.value =
|
||||
prop.allLocations.associateBy { sensorLocationInternal ->
|
||||
@@ -119,15 +120,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun sensorStrengthIntToObject(value: Int): SensorStrength {
|
||||
return when (value) {
|
||||
0 -> SensorStrength.CONVENIENCE
|
||||
1 -> SensorStrength.WEAK
|
||||
2 -> SensorStrength.STRONG
|
||||
else -> throw IllegalArgumentException("Invalid SensorStrength value: $value")
|
||||
}
|
||||
}
|
||||
|
||||
private fun sensorTypeIntToObject(value: Int): FingerprintSensorType {
|
||||
return when (value) {
|
||||
0 -> FingerprintSensorType.UNKNOWN
|
||||
|
||||
@@ -18,9 +18,18 @@ package com.android.systemui.biometrics.shared.model
|
||||
|
||||
import android.hardware.biometrics.SensorProperties
|
||||
|
||||
/** Fingerprint sensor security strength. Represents [SensorProperties.Strength]. */
|
||||
/** Sensor security strength. Represents [SensorProperties.Strength]. */
|
||||
enum class SensorStrength {
|
||||
CONVENIENCE,
|
||||
WEAK,
|
||||
STRONG,
|
||||
}
|
||||
|
||||
/** Convert [this] to corresponding [SensorStrength] */
|
||||
fun Int.toSensorStrength(): SensorStrength =
|
||||
when (this) {
|
||||
0 -> SensorStrength.CONVENIENCE
|
||||
1 -> SensorStrength.WEAK
|
||||
2 -> SensorStrength.STRONG
|
||||
else -> throw IllegalArgumentException("Invalid SensorStrength value: $this")
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ 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
|
||||
@@ -58,6 +60,7 @@ import java.util.stream.Collectors
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -68,6 +71,7 @@ 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
|
||||
@@ -120,6 +124,7 @@ interface DeviceEntryFaceAuthRepository {
|
||||
fun cancel()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SysUISingleton
|
||||
class DeviceEntryFaceAuthRepositoryImpl
|
||||
@Inject
|
||||
@@ -143,7 +148,8 @@ constructor(
|
||||
@FaceDetectTableLog private val faceDetectLog: TableLogBuffer,
|
||||
@FaceAuthTableLog private val faceAuthLog: TableLogBuffer,
|
||||
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||
private val featureFlags: FeatureFlags,
|
||||
featureFlags: FeatureFlags,
|
||||
facePropertyRepository: FacePropertyRepository,
|
||||
dumpManager: DumpManager,
|
||||
) : DeviceEntryFaceAuthRepository, Dumpable {
|
||||
private var authCancellationSignal: CancellationSignal? = null
|
||||
@@ -163,6 +169,13 @@ constructor(
|
||||
override val detectionStatus: Flow<FaceDetectionStatus>
|
||||
get() = _detectionStatus.filterNotNull()
|
||||
|
||||
private val isFaceBiometricsAllowed: Flow<Boolean> =
|
||||
facePropertyRepository.sensorInfo.flatMapLatest {
|
||||
if (it?.strength == SensorStrength.STRONG)
|
||||
biometricSettingsRepository.isStrongBiometricAllowed
|
||||
else biometricSettingsRepository.isNonStrongBiometricAllowed
|
||||
}
|
||||
|
||||
private val _isLockedOut = MutableStateFlow(false)
|
||||
override val isLockedOut: StateFlow<Boolean> = _isLockedOut
|
||||
|
||||
@@ -274,10 +287,8 @@ constructor(
|
||||
canFaceAuthOrDetectRun(faceDetectLog),
|
||||
logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog),
|
||||
logAndObserve(
|
||||
biometricSettingsRepository.isNonStrongBiometricAllowed
|
||||
.isFalse()
|
||||
.or(trustRepository.isCurrentUserTrusted),
|
||||
"nonStrongBiometricIsNotAllowedOrCurrentUserIsTrusted",
|
||||
isFaceBiometricsAllowed.isFalse().or(trustRepository.isCurrentUserTrusted),
|
||||
"biometricIsNotAllowedOrCurrentUserIsTrusted",
|
||||
faceDetectLog
|
||||
),
|
||||
// We don't want to run face detect if fingerprint can be used to unlock the device
|
||||
@@ -368,21 +379,12 @@ constructor(
|
||||
listOf(
|
||||
canFaceAuthOrDetectRun(faceAuthLog),
|
||||
logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog),
|
||||
logAndObserve(
|
||||
deviceEntryFingerprintAuthRepository.isLockedOut.isFalse(),
|
||||
"fpIsNotLockedOut",
|
||||
faceAuthLog
|
||||
),
|
||||
logAndObserve(
|
||||
trustRepository.isCurrentUserTrusted.isFalse(),
|
||||
"currentUserIsNotTrusted",
|
||||
faceAuthLog
|
||||
),
|
||||
logAndObserve(
|
||||
biometricSettingsRepository.isNonStrongBiometricAllowed,
|
||||
"nonStrongBiometricIsAllowed",
|
||||
faceAuthLog
|
||||
),
|
||||
logAndObserve(isFaceBiometricsAllowed, "isFaceBiometricsAllowed", faceAuthLog),
|
||||
logAndObserve(isAuthenticated.isFalse(), "faceNotAuthenticated", faceAuthLog),
|
||||
)
|
||||
.reduce(::and)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics.data.repository
|
||||
|
||||
import android.hardware.biometrics.SensorProperties
|
||||
import android.hardware.face.FaceManager
|
||||
import android.hardware.face.FaceSensorPropertiesInternal
|
||||
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
import org.mockito.junit.MockitoRule
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@RunWith(JUnit4::class)
|
||||
class FacePropertyRepositoryImplTest : SysuiTestCase() {
|
||||
@JvmField @Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
|
||||
|
||||
private lateinit var underTest: FacePropertyRepository
|
||||
private lateinit var testScope: TestScope
|
||||
|
||||
@Captor private lateinit var callback: ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback>
|
||||
@Mock private lateinit var faceManager: FaceManager
|
||||
@Before
|
||||
fun setup() {
|
||||
testScope = TestScope()
|
||||
underTest = createRepository(faceManager)
|
||||
}
|
||||
|
||||
private fun createRepository(manager: FaceManager? = faceManager) =
|
||||
FacePropertyRepositoryImpl(testScope.backgroundScope, manager)
|
||||
|
||||
@Test
|
||||
fun whenFaceManagerIsNotPresentIsNull() =
|
||||
testScope.runTest {
|
||||
underTest = createRepository(null)
|
||||
val sensor = collectLastValue(underTest.sensorInfo)
|
||||
|
||||
assertThat(sensor()).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun providesTheValuePassedToTheAuthenticatorsRegisteredCallback() {
|
||||
testScope.runTest {
|
||||
val sensor by collectLastValue(underTest.sensorInfo)
|
||||
runCurrent()
|
||||
verify(faceManager).addAuthenticatorsRegisteredCallback(callback.capture())
|
||||
|
||||
callback.value.onAllAuthenticatorsRegistered(
|
||||
listOf(createSensorProperties(1, SensorProperties.STRENGTH_STRONG))
|
||||
)
|
||||
|
||||
assertThat(sensor).isEqualTo(FaceSensorInfo(1, SensorStrength.STRONG))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSensorProperties(id: Int, strength: Int) =
|
||||
FaceSensorPropertiesInternal(id, strength, 0, emptyList(), 1, false, false, false)
|
||||
}
|
||||
@@ -40,6 +40,9 @@ 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
|
||||
@@ -151,6 +154,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
|
||||
private lateinit var fakeCommandQueue: FakeCommandQueue
|
||||
private lateinit var featureFlags: FakeFeatureFlags
|
||||
private lateinit var fakeFacePropertyRepository: FakeFacePropertyRepository
|
||||
|
||||
private var wasAuthCancelled = false
|
||||
private var wasDetectCancelled = false
|
||||
@@ -224,6 +228,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
repository = keyguardTransitionRepository,
|
||||
)
|
||||
.keyguardTransitionInteractor
|
||||
fakeFacePropertyRepository = FakeFacePropertyRepository()
|
||||
return DeviceEntryFaceAuthRepositoryImpl(
|
||||
mContext,
|
||||
fmOverride,
|
||||
@@ -245,6 +250,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
faceAuthBuffer,
|
||||
keyguardTransitionInteractor,
|
||||
featureFlags,
|
||||
fakeFacePropertyRepository,
|
||||
dumpManager,
|
||||
)
|
||||
}
|
||||
@@ -590,6 +596,17 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunWhenStrongBiometricIsNotAllowedAndFaceSensorIsStrong() =
|
||||
testScope.runTest {
|
||||
fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
|
||||
runCurrent()
|
||||
|
||||
testGatingCheckForFaceAuth(isFaceStrong = true) {
|
||||
biometricSettingsRepository.setIsStrongBiometricAllowed(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunWhenSecureCameraIsActive() =
|
||||
testScope.runTest {
|
||||
@@ -922,6 +939,19 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectDoesNotRunIfUdfpsIsRunning() =
|
||||
testScope.runTest {
|
||||
@@ -1013,9 +1043,12 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
faceAuthenticateIsCalled()
|
||||
}
|
||||
|
||||
private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) {
|
||||
private suspend fun TestScope.testGatingCheckForFaceAuth(
|
||||
isFaceStrong: Boolean = false,
|
||||
gatingCheckModifier: () -> Unit
|
||||
) {
|
||||
initCollectors()
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
allPreconditionsToRunFaceAuthAreTrue(isFaceStrong)
|
||||
|
||||
gatingCheckModifier()
|
||||
runCurrent()
|
||||
@@ -1024,7 +1057,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
assertThat(underTest.canRunFaceAuth.value).isFalse()
|
||||
|
||||
// flip the gating check back on.
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
allPreconditionsToRunFaceAuthAreTrue(isFaceStrong)
|
||||
|
||||
triggerFaceAuth(false)
|
||||
|
||||
@@ -1043,12 +1076,19 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
faceAuthenticateIsNotCalled()
|
||||
}
|
||||
|
||||
private suspend fun TestScope.testGatingCheckForDetect(gatingCheckModifier: () -> Unit) {
|
||||
private suspend fun TestScope.testGatingCheckForDetect(
|
||||
isFaceStrong: Boolean = false,
|
||||
gatingCheckModifier: () -> Unit
|
||||
) {
|
||||
initCollectors()
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
|
||||
// This will stop face auth from running but is required to be false for detect.
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
|
||||
if (isFaceStrong) {
|
||||
biometricSettingsRepository.setStrongBiometricAllowed(false)
|
||||
} else {
|
||||
// This will stop face auth from running but is required to be false for detect.
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
|
||||
}
|
||||
runCurrent()
|
||||
|
||||
assertThat(canFaceAuthRun()).isFalse()
|
||||
@@ -1083,7 +1123,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
cancellationSignal.value.setOnCancelListener { wasAuthCancelled = true }
|
||||
}
|
||||
|
||||
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() {
|
||||
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue(
|
||||
isFaceStrong: Boolean = false
|
||||
) {
|
||||
verify(faceManager, atLeastOnce())
|
||||
.addLockoutResetCallback(faceLockoutResetCallback.capture())
|
||||
biometricSettingsRepository.setFaceEnrolled(true)
|
||||
@@ -1098,7 +1140,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
WakeSleepReason.OTHER
|
||||
)
|
||||
)
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(true)
|
||||
if (isFaceStrong) {
|
||||
biometricSettingsRepository.setStrongBiometricAllowed(true)
|
||||
} else {
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(true)
|
||||
}
|
||||
biometricSettingsRepository.setIsUserInLockdown(false)
|
||||
fakeUserRepository.setSelectedUserInfo(primaryUser)
|
||||
biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
|
||||
|
||||
@@ -342,12 +342,13 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceUnlockIsDisabledWhenFpIsLockedOut() = testScope.runTest {
|
||||
underTest.start()
|
||||
fun faceUnlockIsDisabledWhenFpIsLockedOut() =
|
||||
testScope.runTest {
|
||||
underTest.start()
|
||||
|
||||
fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
|
||||
runCurrent()
|
||||
fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
|
||||
runCurrent()
|
||||
|
||||
assertThat(faceAuthRepository.wasDisabled).isTrue()
|
||||
}
|
||||
assertThat(faceAuthRepository.wasDisabled).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics.data.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeFacePropertyRepository : FacePropertyRepository {
|
||||
private val faceSensorInfo = MutableStateFlow<FaceSensorInfo?>(null)
|
||||
override val sensorInfo: Flow<FaceSensorInfo?>
|
||||
get() = faceSensorInfo
|
||||
|
||||
fun setSensorInfo(value: FaceSensorInfo?) {
|
||||
faceSensorInfo.value = value
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,6 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
|
||||
private val _authFlags = MutableStateFlow(AuthenticationFlags(0, 0))
|
||||
override val authenticationFlags: Flow<AuthenticationFlags>
|
||||
get() = _authFlags
|
||||
|
||||
fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) {
|
||||
_isFingerprintEnrolled.value = isFingerprintEnrolled
|
||||
}
|
||||
@@ -110,4 +109,8 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
|
||||
fun setIsNonStrongBiometricAllowed(value: Boolean) {
|
||||
_isNonStrongBiometricAllowed.value = value
|
||||
}
|
||||
|
||||
fun setIsStrongBiometricAllowed(value: Boolean) {
|
||||
_isStrongBiometricAllowed.value = value
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user