Merge "Fingerprint allowed state should update based on face lockout" into main
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index 4fd44cc..cfe0bec 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
@@ -108,7 +109,9 @@
facePropertyRepository = kosmos.fakeFacePropertyRepository,
deviceEntryFingerprintAuthInteractor = kosmos.deviceEntryFingerprintAuthInteractor,
faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository,
- securityModel = securityModel
+ securityModel = securityModel,
+ deviceEntryBiometricsAllowedInteractor =
+ kosmos.deviceEntryBiometricsAllowedInteractor,
)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(
fingerprintAuthCurrentlyAllowed
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
index 51f9957..605d125 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
@@ -21,8 +21,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -36,41 +34,29 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val underTest = kosmos.deviceEntryFingerprintAuthInteractor
- private val fingerprintAuthRepository = kosmos.deviceEntryFingerprintAuthRepository
private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
- private val biometricSettingsRepository = kosmos.biometricSettingsRepository
@Test
- fun isFingerprintAuthCurrentlyAllowed_allowedOnlyWhenItIsNotLockedOutAndAllowedBySettings() =
+ fun isSensorUnderDisplay() =
testScope.runTest {
- val currentlyAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
- fingerprintAuthRepository.setLockedOut(true)
-
- assertThat(currentlyAllowed).isFalse()
-
- fingerprintAuthRepository.setLockedOut(false)
- assertThat(currentlyAllowed).isTrue()
-
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
- assertThat(currentlyAllowed).isFalse()
+ val isUdfps by collectLastValue(underTest.isSensorUnderDisplay)
+ fingerprintPropertyRepository.supportsUdfps()
+ assertThat(isUdfps).isTrue()
}
@Test
- fun isFingerprintCurrentlyAllowedInBouncer_trueForNonUdfpsSensorTypes() =
+ fun isSensorUnderDisplay_rear() =
testScope.runTest {
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
-
- val isFingerprintCurrentlyAllowedInBouncer by
- collectLastValue(underTest.isFingerprintCurrentlyAllowedOnBouncer)
-
- fingerprintPropertyRepository.supportsUdfps()
- assertThat(isFingerprintCurrentlyAllowedInBouncer).isFalse()
-
+ val isUdfps by collectLastValue(underTest.isSensorUnderDisplay)
fingerprintPropertyRepository.supportsRearFps()
- assertThat(isFingerprintCurrentlyAllowedInBouncer).isTrue()
+ assertThat(isUdfps).isFalse()
+ }
+ @Test
+ fun isSensorUnderDisplay_side() =
+ testScope.runTest {
+ val isUdfps by collectLastValue(underTest.isSensorUnderDisplay)
fingerprintPropertyRepository.supportsSideFps()
- assertThat(isFingerprintCurrentlyAllowedInBouncer).isTrue()
+ assertThat(isUdfps).isFalse()
}
}
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 4984fc6..373671d0 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
@@ -21,7 +21,7 @@
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -60,7 +60,8 @@
private val biometricSettingsRepository: BiometricSettingsRepository,
private val systemClock: SystemClock,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val deviceEntryFingerprintAuthInteractor: Lazy<DeviceEntryFingerprintAuthInteractor>,
+ private val deviceEntryBiometricsAllowedInteractor:
+ Lazy<DeviceEntryBiometricsAllowedInteractor>,
private val keyguardInteractor: Lazy<KeyguardInteractor>,
keyguardTransitionInteractor: Lazy<KeyguardTransitionInteractor>,
sceneInteractor: Lazy<SceneInteractor>,
@@ -114,7 +115,7 @@
flowOf(false)
} else {
combine(
- deviceEntryFingerprintAuthInteractor
+ deviceEntryBiometricsAllowedInteractor
.get()
.isFingerprintAuthCurrentlyAllowed,
keyguardInteractor.get().isKeyguardDismissible,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index 35015e7..8e12646 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -33,6 +33,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
@@ -76,10 +77,11 @@
private val deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
faceAuthRepository: DeviceEntryFaceAuthRepository,
private val securityModel: KeyguardSecurityModel,
+ deviceEntryBiometricsAllowedInteractor: DeviceEntryBiometricsAllowedInteractor,
) {
private val isFingerprintAuthCurrentlyAllowedOnBouncer =
- deviceEntryFingerprintAuthInteractor.isFingerprintCurrentlyAllowedOnBouncer.stateIn(
+ deviceEntryBiometricsAllowedInteractor.isFingerprintCurrentlyAllowedOnBouncer.stateIn(
applicationScope,
SharingStarted.Eagerly,
false
@@ -87,6 +89,7 @@
private val currentSecurityMode
get() = securityModel.getSecurityMode(currentUserId)
+
private val currentUserId
get() = userRepository.getSelectedUserInfo().id
@@ -349,6 +352,7 @@
interface CountDownTimerCallback {
fun onFinish()
+
fun onTick(millisUntilFinished: Long)
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/log/BouncerLoggerStartable.kt b/packages/SystemUI/src/com/android/systemui/bouncer/log/BouncerLoggerStartable.kt
index 29c4f2e..87ec254 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/log/BouncerLoggerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/log/BouncerLoggerStartable.kt
@@ -20,6 +20,7 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricSettingsInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.log.BouncerLogger
@@ -39,6 +40,7 @@
private val faceAuthInteractor: DeviceEntryFaceAuthInteractor,
private val fingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
private val bouncerLogger: BouncerLogger,
+ private val deviceEntryBiometricsAllowedInteractor: DeviceEntryBiometricsAllowedInteractor,
) : CoreStartable {
override fun start() {
if (!Build.isDebuggable()) {
@@ -69,13 +71,13 @@
}
}
applicationScope.launch {
- fingerprintAuthInteractor.isFingerprintCurrentlyAllowedOnBouncer.collectLatest {
- newValue ->
- bouncerLogger.interestedStateChanged(
- "fingerprintCurrentlyAllowedOnBouncer",
- newValue
- )
- }
+ deviceEntryBiometricsAllowedInteractor.isFingerprintCurrentlyAllowedOnBouncer
+ .collectLatest { newValue ->
+ bouncerLogger.interestedStateChanged(
+ "fingerprintCurrentlyAllowedOnBouncer",
+ newValue
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
index 810b6d1..31479f1 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
@@ -30,8 +30,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.deviceentry.shared.model.DeviceEntryRestrictionReason
import com.android.systemui.deviceentry.shared.model.FaceFailureMessage
@@ -76,7 +76,7 @@
private val biometricMessageInteractor: BiometricMessageInteractor,
private val faceAuthInteractor: DeviceEntryFaceAuthInteractor,
private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
- private val fingerprintInteractor: DeviceEntryFingerprintAuthInteractor,
+ private val deviceEntryBiometricsAllowedInteractor: DeviceEntryBiometricsAllowedInteractor,
flags: ComposeBouncerFlags,
) {
/**
@@ -121,7 +121,8 @@
combine(
deviceUnlockedInteractor.deviceEntryRestrictionReason,
lockoutMessage,
- fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer,
+ deviceEntryBiometricsAllowedInteractor
+ .isFingerprintCurrentlyAllowedOnBouncer,
resetToDefault,
) { deviceEntryRestrictedReason, lockoutMsg, isFpAllowedInBouncer, _ ->
lockoutMsg
@@ -168,7 +169,7 @@
biometricMessageInteractor.faceMessage
.sample(
authenticationInteractor.authenticationMethod,
- fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer,
+ deviceEntryBiometricsAllowedInteractor.isFingerprintCurrentlyAllowedOnBouncer,
)
.collectLatest { (faceMessage, authMethod, fingerprintAllowedOnBouncer) ->
val isFaceAuthStrong = faceAuthInteractor.isFaceAuthStrong()
@@ -223,7 +224,7 @@
biometricMessageInteractor.fingerprintMessage
.sample(
authenticationInteractor.authenticationMethod,
- fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer
+ deviceEntryBiometricsAllowedInteractor.isFingerprintCurrentlyAllowedOnBouncer
)
.collectLatest { (fingerprintMessage, authMethod, isFingerprintAllowed) ->
val defaultPrimaryMessage =
@@ -261,7 +262,7 @@
bouncerInteractor.onIncorrectBouncerInput
.sample(
authenticationInteractor.authenticationMethod,
- fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer
+ deviceEntryBiometricsAllowedInteractor.isFingerprintCurrentlyAllowedOnBouncer
)
.collectLatest { (_, authMethod, isFingerprintAllowed) ->
message.emit(
@@ -414,7 +415,7 @@
biometricMessageInteractor: BiometricMessageInteractor,
faceAuthInteractor: DeviceEntryFaceAuthInteractor,
deviceUnlockedInteractor: DeviceUnlockedInteractor,
- fingerprintInteractor: DeviceEntryFingerprintAuthInteractor,
+ deviceEntryBiometricsAllowedInteractor: DeviceEntryBiometricsAllowedInteractor,
flags: ComposeBouncerFlags,
userSwitcherViewModel: UserSwitcherViewModel,
): BouncerMessageViewModel {
@@ -428,7 +429,7 @@
biometricMessageInteractor = biometricMessageInteractor,
faceAuthInteractor = faceAuthInteractor,
deviceUnlockedInteractor = deviceUnlockedInteractor,
- fingerprintInteractor = fingerprintInteractor,
+ deviceEntryBiometricsAllowedInteractor = deviceEntryBiometricsAllowedInteractor,
flags = flags,
selectedUser = userSwitcherViewModel.selectedUser,
)
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractor.kt
new file mode 100644
index 0000000..79b176c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractor.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 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.deviceentry.domain.interactor
+
+import com.android.systemui.biometrics.data.repository.FacePropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/**
+ * Individual biometrics (ie: fingerprint or face) may not be allowed to be used based on the
+ * lockout states of biometrics of the same or higher sensor strength.
+ *
+ * This class coordinates the lockout states of each individual biometric based on the lockout
+ * states of other biometrics.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class DeviceEntryBiometricsAllowedInteractor
+@Inject
+constructor(
+ deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
+ deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
+ biometricSettingsInteractor: DeviceEntryBiometricSettingsInteractor,
+ facePropertyRepository: FacePropertyRepository,
+) {
+
+ private val isStrongFaceAuth: Flow<Boolean> =
+ facePropertyRepository.sensorInfo.map { it?.strength == SensorStrength.STRONG }
+
+ private val isStrongFaceAuthLockedOut: Flow<Boolean> =
+ combine(isStrongFaceAuth, deviceEntryFaceAuthInteractor.isLockedOut) {
+ isStrongFaceAuth,
+ isFaceAuthLockedOut ->
+ isStrongFaceAuth && isFaceAuthLockedOut
+ }
+
+ /**
+ * Whether fingerprint authentication is currently allowed for the user. This is true if the
+ * user has fingerprint auth enabled, enrolled, it is not disabled by any security timeouts by
+ * [com.android.systemui.keyguard.shared.model.AuthenticationFlags], not locked out due to too
+ * many incorrect attempts, and other biometrics at a higher or equal strenght are not locking
+ * fingerprint out.
+ */
+ val isFingerprintAuthCurrentlyAllowed: Flow<Boolean> =
+ combine(
+ deviceEntryFingerprintAuthInteractor.isLockedOut,
+ biometricSettingsInteractor.fingerprintAuthCurrentlyAllowed,
+ isStrongFaceAuthLockedOut,
+ ) { fpLockedOut, fpAllowedBySettings, strongAuthFaceAuthLockedOut ->
+ !fpLockedOut && fpAllowedBySettings && !strongAuthFaceAuthLockedOut
+ }
+
+ /** Whether fingerprint authentication is currently allowed while on the bouncer. */
+ val isFingerprintCurrentlyAllowedOnBouncer =
+ deviceEntryFingerprintAuthInteractor.isSensorUnderDisplay.flatMapLatest { sensorBelowDisplay
+ ->
+ if (sensorBelowDisplay) {
+ flowOf(false)
+ } else {
+ isFingerprintAuthCurrentlyAllowed
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt
index a5eafa9..969f53f 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt
@@ -29,10 +29,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterIsInstance
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@OptIn(ExperimentalCoroutinesApi::class)
@@ -70,29 +67,9 @@
repository.authenticationStatus.filterIsInstance<SuccessFingerprintAuthenticationStatus>()
/**
- * Whether fingerprint authentication is currently allowed for the user. This is true if the
- * user has fingerprint auth enabled, enrolled, it is not disabled by any security timeouts by
- * [com.android.systemui.keyguard.shared.model.AuthenticationFlags] and not locked out due to
- * too many incorrect attempts.
- */
- val isFingerprintAuthCurrentlyAllowed: Flow<Boolean> =
- combine(isLockedOut, biometricSettingsInteractor.fingerprintAuthCurrentlyAllowed, ::Pair)
- .map { (lockedOut, currentlyAllowed) -> !lockedOut && currentlyAllowed }
-
- /**
* Whether the fingerprint sensor is present under the display as opposed to being on the power
* button or behind/rear of the phone.
*/
val isSensorUnderDisplay =
fingerprintPropertyRepository.sensorType.map(FingerprintSensorType::isUdfps)
-
- /** Whether fingerprint authentication is currently allowed while on the bouncer. */
- val isFingerprintCurrentlyAllowedOnBouncer =
- isSensorUnderDisplay.flatMapLatest { sensorBelowDisplay ->
- if (sensorBelowDisplay) {
- flowOf(false)
- } else {
- isFingerprintAuthCurrentlyAllowed
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
new file mode 100644
index 0000000..295a626
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 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.deviceentry.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+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.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryBiometricsAllowedInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val underTest = kosmos.deviceEntryBiometricsAllowedInteractor
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowed_true() =
+ testScope.runTest {
+ val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
+
+ // WHEN: not locked out, no face sensor, no strong auth requirements
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeFacePropertyRepository.setSensorInfo(null)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ // THEN fp is allowed
+ assertThat(fpAllowed).isTrue()
+ }
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowed_strongFaceLockedOut() =
+ testScope.runTest {
+ val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
+
+ // WHEN: not locked out, face is strong & locked out, no strong auth requirements
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeFacePropertyRepository.setSensorInfo(
+ FaceSensorInfo(
+ id = 0,
+ strength = SensorStrength.STRONG,
+ )
+ )
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ // THEN fp is NOT allowed
+ assertThat(fpAllowed).isFalse()
+ }
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowed_convenienceFaceLockedOut() =
+ testScope.runTest {
+ val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
+
+ // WHEN: not locked out, face is convenience & locked out, no strong auth requirements
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeFacePropertyRepository.setSensorInfo(
+ FaceSensorInfo(
+ id = 0,
+ strength = SensorStrength.CONVENIENCE,
+ )
+ )
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ // THEN fp is allowed
+ assertThat(fpAllowed).isTrue()
+ }
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowed_primaryAuthRequired() =
+ testScope.runTest {
+ val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
+
+ // WHEN: not locked out, no face sensor, no strong auth requirements
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
+
+ // THEN fp is NOT allowed
+ assertThat(fpAllowed).isFalse()
+ }
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowedOnBouncer_sfps() =
+ testScope.runTest {
+ val fpAllowedOnBouncer by
+ collectLastValue(underTest.isFingerprintCurrentlyAllowedOnBouncer)
+
+ // GIVEN fingerprint is generally allowed
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ // WHEN side fps
+ kosmos.fakeFingerprintPropertyRepository.supportsSideFps()
+
+ // THEN fp is allowed on the primary bouncer
+ assertThat(fpAllowedOnBouncer).isTrue()
+ }
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowedOnBouncer_rearFps() =
+ testScope.runTest {
+ val fpAllowedOnBouncer by
+ collectLastValue(underTest.isFingerprintCurrentlyAllowedOnBouncer)
+
+ // GIVEN fingerprint is generally allowed
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ // WHEN rear fps
+ kosmos.fakeFingerprintPropertyRepository.supportsRearFps()
+
+ // THEN fp is allowed on the primary bouncer
+ assertThat(fpAllowedOnBouncer).isTrue()
+ }
+
+ @Test
+ fun isFingerprintAuthCurrentlyAllowedOnBouncer_udfps() =
+ testScope.runTest {
+ val fpAllowedOnBouncer by
+ collectLastValue(underTest.isFingerprintCurrentlyAllowedOnBouncer)
+
+ // GIVEN fp is generally allowed
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ // WHEN UDFPS
+ kosmos.fakeFingerprintPropertyRepository.supportsUdfps()
+
+ // THEN fp is never allowed on the primary bouncer
+ assertThat(fpAllowedOnBouncer).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
index a8271c1..2a2a82d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -31,8 +31,8 @@
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
@@ -112,7 +112,7 @@
biometricSettingsRepository,
FakeSystemClock(),
keyguardUpdateMonitor,
- { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
+ { mock(DeviceEntryBiometricsAllowedInteractor::class.java) },
{ mock(KeyguardInteractor::class.java) },
{ mock(KeyguardTransitionInteractor::class.java) },
{ kosmos.sceneInteractor },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
index 9236bd2..63323b2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
@@ -19,9 +19,10 @@
import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
@@ -42,7 +43,7 @@
biometricSettingsRepository = biometricSettingsRepository,
systemClock = systemClock,
keyguardUpdateMonitor = keyguardUpdateMonitor,
- deviceEntryFingerprintAuthInteractor = { deviceEntryFingerprintAuthInteractor },
+ deviceEntryBiometricsAllowedInteractor = { deviceEntryBiometricsAllowedInteractor },
keyguardInteractor = { keyguardInteractor },
keyguardTransitionInteractor = { keyguardTransitionInteractor },
scope = testScope.backgroundScope,
@@ -55,6 +56,7 @@
this.keyguardBouncerRepository.setPrimaryShow(false)
this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
this.biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ this.deviceEntryFaceAuthRepository.setLockedOut(false)
whenever(this.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
whenever(this.keyguardStateController.isUnlocked).thenReturn(false)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt
index de5f0f3..e70631e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt
@@ -22,8 +22,8 @@
import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
import com.android.systemui.bouncer.shared.flag.composeBouncerFlags
import com.android.systemui.deviceentry.domain.interactor.biometricMessageInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
@@ -45,7 +45,7 @@
biometricMessageInteractor = biometricMessageInteractor,
faceAuthInteractor = deviceEntryFaceAuthInteractor,
deviceUnlockedInteractor = deviceUnlockedInteractor,
- fingerprintInteractor = deviceEntryFingerprintAuthInteractor,
+ deviceEntryBiometricsAllowedInteractor = deviceEntryBiometricsAllowedInteractor,
flags = composeBouncerFlags,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt
new file mode 100644
index 0000000..4357289
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.deviceentry.domain.interactor
+
+import com.android.systemui.biometrics.data.repository.facePropertyRepository
+import com.android.systemui.kosmos.Kosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+val Kosmos.deviceEntryBiometricsAllowedInteractor by
+ Kosmos.Fixture {
+ DeviceEntryBiometricsAllowedInteractor(
+ deviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor,
+ deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
+ biometricSettingsInteractor = deviceEntryBiometricSettingsInteractor,
+ facePropertyRepository = facePropertyRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
index be8048e..9b7bca6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
@@ -27,8 +27,8 @@
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryBiometricsAllowedInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -87,7 +87,7 @@
FakeBiometricSettingsRepository(),
FakeSystemClock(),
keyguardUpdateMonitor,
- { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
+ { mock(DeviceEntryBiometricsAllowedInteractor::class.java) },
{ mock(KeyguardInteractor::class.java) },
{ mock(KeyguardTransitionInteractor::class.java) },
{ mock(SceneInteractor::class.java) },