From 825a9c8b809d16973c62a44c2f2701939cdd50e6 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Wed, 19 Jul 2023 20:12:18 -0700 Subject: [PATCH 1/2] Add FaceSensorRepository to provide the face sensor state when it becomes available. Following the pattern followed by FingerprintPropertyRepository Bug: 275788040 Test: atest FaceSensorRepositoryImplTest Change-Id: I261a3f3ef2d11a7842316e4bb5397012b31df2c7 --- .../biometrics/dagger/BiometricsModule.kt | 6 ++ .../data/repository/FacePropertyRepository.kt | 81 +++++++++++++++++ .../FingerprintPropertyRepository.kt | 12 +-- .../biometrics/shared/model/SensorStrength.kt | 11 ++- .../FacePropertyRepositoryImplTest.kt | 91 +++++++++++++++++++ .../repository/FakeFacePropertyRepository.kt | 31 +++++++ 6 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt create mode 100644 packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt index a5e846ad61ca7..53dc0e3d48464 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt new file mode 100644 index 0000000000000..d2cb849452520 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt @@ -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 +} + +/** 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> = + faceManager?.let { + ConflatedCallbackFlow.conflatedCallbackFlow { + val callback = + object : IFaceAuthenticatorsRegisteredCallback.Stub() { + override fun onAllAuthenticatorsRegistered( + sensors: List + ) { + trySendWithFailureLogging( + sensors, + TAG, + "onAllAuthenticatorsRegistered" + ) + } + } + it.addAuthenticatorsRegisteredCallback(callback) + awaitClose {} + } + .shareIn(applicationScope, SharingStarted.Eagerly) + } + ?: flowOf(emptyList()) + + override val sensorInfo: Flow = + sensorProps + .map { it.firstOrNull() } + .map { it?.let { FaceSensorInfo(it.sensorId, it.sensorStrength.toSensorStrength()) } } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt index efc92ad3b4c80..daff5feb01231 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt index 2982d0be3764e..30e865eff8b8a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt @@ -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") + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt new file mode 100644 index 0000000000000..fcc40404bf7d5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt @@ -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 + @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) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt new file mode 100644 index 0000000000000..2ef1be70000fd --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt @@ -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(null) + override val sensorInfo: Flow + get() = faceSensorInfo + + fun setSensorInfo(value: FaceSensorInfo?) { + faceSensorInfo.value = value + } +} From a15b1b795725b8f5fd859f5f6229dd4a72ccb5c6 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Wed, 19 Jul 2023 20:20:06 -0700 Subject: [PATCH 2/2] Support class 3 face auth Depending on the strength of the face sensor we will use either `BiometricSettingsRepository#isStrongBiometricAllowed` or `BiometricSettingsRepository#isNonStrongBiometricAllowed` Fixes: 275788040 Test: atest DeviceEntryFaceAuthRepositoryTest Change-Id: I1a0a4767830fc0150fdc9c17ee19bd66d30d2814 --- .../DeviceEntryFaceAuthRepository.kt | 32 +++++----- .../DeviceEntryFaceAuthRepositoryTest.kt | 62 ++++++++++++++++--- .../KeyguardFaceAuthInteractorTest.kt | 13 ++-- .../FakeBiometricSettingsRepository.kt | 5 +- 4 files changed, 82 insertions(+), 30 deletions(-) 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 bf1e75b09bac4..6fd3e21b25a4d 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,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 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 @@ -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) 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 b3f800087bdf0..01a6c64a6898e 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,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) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index 8c9ed5b2ef4ea..8636dd8df3b03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -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() + } } 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 4aaf3478a31df..8c98aea6a9900 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 @@ -59,7 +59,6 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository { private val _authFlags = MutableStateFlow(AuthenticationFlags(0, 0)) override val authenticationFlags: Flow 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 + } }