Merge "Minor cleanup: move logic that locks face whenever fingerprint is locked to the interactor" into udc-qpr-dev
This commit is contained in:
@@ -102,6 +102,9 @@ interface DeviceEntryFaceAuthRepository {
|
||||
/** Whether bypass is currently enabled */
|
||||
val isBypassEnabled: Flow<Boolean>
|
||||
|
||||
/** Set whether face authentication should be locked out or not */
|
||||
fun lockoutFaceAuth()
|
||||
|
||||
/**
|
||||
* Trigger face authentication.
|
||||
*
|
||||
@@ -199,6 +202,10 @@ constructor(
|
||||
}
|
||||
?: flowOf(false)
|
||||
|
||||
override fun lockoutFaceAuth() {
|
||||
_isLockedOut.value = true
|
||||
}
|
||||
|
||||
private val faceLockoutResetCallback =
|
||||
object : FaceManager.LockoutResetCallback() {
|
||||
override fun onLockoutReset(sensorId: Int) {
|
||||
@@ -396,7 +403,7 @@ constructor(
|
||||
private val faceAuthCallback =
|
||||
object : FaceManager.AuthenticationCallback() {
|
||||
override fun onAuthenticationFailed() {
|
||||
_authenticationStatus.value = FailedFaceAuthenticationStatus
|
||||
_authenticationStatus.value = FailedFaceAuthenticationStatus()
|
||||
_isAuthenticated.value = false
|
||||
faceAuthLogger.authenticationFailed()
|
||||
onFaceAuthRequestCompleted()
|
||||
|
||||
@@ -55,6 +55,8 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
|
||||
override val isBypassEnabled: Flow<Boolean>
|
||||
get() = emptyFlow()
|
||||
|
||||
override fun lockoutFaceAuth() = Unit
|
||||
|
||||
/**
|
||||
* Trigger face authentication.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
|
||||
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
|
||||
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
|
||||
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
@@ -67,6 +68,7 @@ constructor(
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val faceAuthenticationLogger: FaceAuthenticationLogger,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
|
||||
) : CoreStartable, KeyguardFaceAuthInteractor {
|
||||
|
||||
private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
|
||||
@@ -117,6 +119,15 @@ constructor(
|
||||
)
|
||||
}
|
||||
.launchIn(applicationScope)
|
||||
|
||||
deviceEntryFingerprintAuthRepository.isLockedOut
|
||||
.onEach {
|
||||
if (it) {
|
||||
faceAuthenticationLogger.faceLockedOut("Fingerprint locked out")
|
||||
repository.lockoutFaceAuth()
|
||||
}
|
||||
}
|
||||
.launchIn(applicationScope)
|
||||
}
|
||||
|
||||
override fun onSwipeUpOnBouncer() {
|
||||
|
||||
@@ -23,29 +23,40 @@ import android.os.SystemClock.elapsedRealtime
|
||||
* Authentication status provided by
|
||||
* [com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository]
|
||||
*/
|
||||
sealed class FaceAuthenticationStatus(
|
||||
// present to break equality check if the same error occurs repeatedly.
|
||||
val createdAt: Long = elapsedRealtime()
|
||||
)
|
||||
sealed class FaceAuthenticationStatus
|
||||
|
||||
/** Success authentication status. */
|
||||
data class SuccessFaceAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) :
|
||||
FaceAuthenticationStatus()
|
||||
data class SuccessFaceAuthenticationStatus(
|
||||
val successResult: FaceManager.AuthenticationResult,
|
||||
// present to break equality check if the same error occurs repeatedly.
|
||||
@JvmField val createdAt: Long = elapsedRealtime()
|
||||
) : FaceAuthenticationStatus()
|
||||
|
||||
/** Face authentication help message. */
|
||||
data class HelpFaceAuthenticationStatus(val msgId: Int, val msg: String?) :
|
||||
FaceAuthenticationStatus()
|
||||
data class HelpFaceAuthenticationStatus(
|
||||
val msgId: Int,
|
||||
val msg: String?, // present to break equality check if the same error occurs repeatedly.
|
||||
@JvmField val createdAt: Long = elapsedRealtime()
|
||||
) : FaceAuthenticationStatus()
|
||||
|
||||
/** Face acquired message. */
|
||||
data class AcquiredFaceAuthenticationStatus(val acquiredInfo: Int) : FaceAuthenticationStatus()
|
||||
data class AcquiredFaceAuthenticationStatus(
|
||||
val acquiredInfo: Int, // present to break equality check if the same error occurs repeatedly.
|
||||
@JvmField val createdAt: Long = elapsedRealtime()
|
||||
) : FaceAuthenticationStatus()
|
||||
|
||||
/** Face authentication failed message. */
|
||||
object FailedFaceAuthenticationStatus : FaceAuthenticationStatus()
|
||||
data class FailedFaceAuthenticationStatus(
|
||||
// present to break equality check if the same error occurs repeatedly.
|
||||
@JvmField val createdAt: Long = elapsedRealtime()
|
||||
) : FaceAuthenticationStatus()
|
||||
|
||||
/** Face authentication error message */
|
||||
data class ErrorFaceAuthenticationStatus(
|
||||
val msgId: Int,
|
||||
val msg: String? = null,
|
||||
// present to break equality check if the same error occurs repeatedly.
|
||||
@JvmField val createdAt: Long = elapsedRealtime()
|
||||
) : FaceAuthenticationStatus() {
|
||||
/**
|
||||
* Method that checks if [msgId] is a lockout error. A lockout error means that face
|
||||
@@ -80,5 +91,5 @@ data class FaceDetectionStatus(
|
||||
val userId: Int,
|
||||
val isStrongBiometric: Boolean,
|
||||
// present to break equality check if the same error occurs repeatedly.
|
||||
val createdAt: Long = elapsedRealtime()
|
||||
@JvmField val createdAt: Long = elapsedRealtime()
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.log.core.LogLevel.DEBUG
|
||||
import com.android.systemui.log.dagger.FaceAuthLog
|
||||
import com.google.errorprone.annotations.CompileTimeConstant
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val TAG = "DeviceEntryFaceAuthRepositoryLog"
|
||||
@@ -264,4 +265,8 @@ constructor(
|
||||
fun watchdogScheduled() {
|
||||
logBuffer.log(TAG, DEBUG, "FaceManager Biometric watchdog scheduled.")
|
||||
}
|
||||
|
||||
fun faceLockedOut(@CompileTimeConstant reason: String) {
|
||||
logBuffer.log(TAG, DEBUG, "Face auth has been locked out: $reason")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
val successResult = successResult()
|
||||
authenticationCallback.value.onAuthenticationSucceeded(successResult)
|
||||
|
||||
assertThat(authStatus()).isEqualTo(SuccessFaceAuthenticationStatus(successResult))
|
||||
val response = authStatus() as SuccessFaceAuthenticationStatus
|
||||
assertThat(response.successResult).isEqualTo(successResult)
|
||||
assertThat(authenticated()).isTrue()
|
||||
assertThat(authRunning()).isFalse()
|
||||
assertThat(canFaceAuthRun()).isFalse()
|
||||
@@ -494,7 +495,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
authenticationCallback.value.onAuthenticationHelp(10, "Ignored help msg")
|
||||
authenticationCallback.value.onAuthenticationHelp(11, "Ignored help msg")
|
||||
|
||||
assertThat(authStatus()).isEqualTo(HelpFaceAuthenticationStatus(9, "help msg"))
|
||||
val response = authStatus() as HelpFaceAuthenticationStatus
|
||||
assertThat(response.msg).isEqualTo("help msg")
|
||||
assertThat(response.msgId).isEqualTo(response.msgId)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -550,10 +553,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunWhenFpIsLockedOut() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForFaceAuth { deviceEntryFingerprintAuthRepository.setLockedOut(true) }
|
||||
}
|
||||
fun authenticateDoesNotRunWhenFaceIsDisabled() =
|
||||
testScope.runTest { testGatingCheckForFaceAuth { underTest.lockoutFaceAuth() } }
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunWhenUserIsCurrentlyTrusted() =
|
||||
@@ -857,6 +858,19 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun disableFaceUnlockLocksOutFaceUnlock() =
|
||||
testScope.runTest {
|
||||
runCurrent()
|
||||
initCollectors()
|
||||
assertThat(underTest.isLockedOut.value).isFalse()
|
||||
|
||||
underTest.lockoutFaceAuth()
|
||||
runCurrent()
|
||||
|
||||
assertThat(underTest.isLockedOut.value).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectDoesNotRunWhenFaceAuthNotSupportedInCurrentPosture() =
|
||||
testScope.runTest {
|
||||
@@ -1070,10 +1084,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() {
|
||||
verify(faceManager, atLeastOnce())
|
||||
.addLockoutResetCallback(faceLockoutResetCallback.capture())
|
||||
biometricSettingsRepository.setFaceEnrolled(true)
|
||||
biometricSettingsRepository.setIsFaceAuthEnabled(true)
|
||||
fakeUserRepository.setUserSwitching(false)
|
||||
deviceEntryFingerprintAuthRepository.setLockedOut(false)
|
||||
trustRepository.setCurrentUserTrusted(false)
|
||||
keyguardRepository.setKeyguardGoingAway(false)
|
||||
keyguardRepository.setWakefulnessModel(
|
||||
@@ -1087,6 +1102,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
biometricSettingsRepository.setIsUserInLockdown(false)
|
||||
fakeUserRepository.setSelectedUserInfo(primaryUser)
|
||||
biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
|
||||
faceLockoutResetCallback.value.onLockoutReset(0)
|
||||
bouncerRepository.setAlternateVisible(true)
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
runCurrent()
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry
|
||||
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
|
||||
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
|
||||
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
|
||||
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
|
||||
@@ -73,6 +74,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
|
||||
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
|
||||
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
|
||||
private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository
|
||||
private lateinit var fakeDeviceEntryFingerprintAuthRepository:
|
||||
FakeDeviceEntryFingerprintAuthRepository
|
||||
|
||||
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
|
||||
@@ -94,6 +97,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
|
||||
)
|
||||
.keyguardTransitionInteractor
|
||||
|
||||
fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
|
||||
underTest =
|
||||
SystemUIKeyguardFaceAuthInteractor(
|
||||
mContext,
|
||||
@@ -127,6 +131,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
|
||||
featureFlags,
|
||||
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
|
||||
keyguardUpdateMonitor,
|
||||
fakeDeviceEntryFingerprintAuthRepository
|
||||
)
|
||||
}
|
||||
|
||||
@@ -335,4 +340,14 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
|
||||
assertThat(faceAuthRepository.runningAuthRequest.value)
|
||||
.isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER, false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceUnlockIsDisabledWhenFpIsLockedOut() = testScope.runTest {
|
||||
underTest.start()
|
||||
|
||||
fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
|
||||
runCurrent()
|
||||
|
||||
assertThat(faceAuthRepository.wasDisabled).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ import kotlinx.coroutines.flow.filterNotNull
|
||||
|
||||
class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
|
||||
|
||||
private var _wasDisabled: Boolean = false
|
||||
|
||||
val wasDisabled: Boolean
|
||||
get() = _wasDisabled
|
||||
|
||||
override val isAuthenticated = MutableStateFlow(false)
|
||||
override val canRunFaceAuth = MutableStateFlow(false)
|
||||
private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null)
|
||||
@@ -52,6 +57,9 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
|
||||
override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
|
||||
|
||||
override val isBypassEnabled = MutableStateFlow(false)
|
||||
override fun lockoutFaceAuth() {
|
||||
_wasDisabled = true
|
||||
}
|
||||
|
||||
override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {
|
||||
_runningAuthRequest.value = uiEvent to fallbackToDetection
|
||||
|
||||
Reference in New Issue
Block a user