Merge "Minor cleanup: move logic that locks face whenever fingerprint is locked to the interactor" into udc-qpr-dev

This commit is contained in:
Chandru S
2023-07-24 03:36:32 +00:00
committed by Android (Google) Code Review
8 changed files with 94 additions and 19 deletions

View File

@@ -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()

View File

@@ -55,6 +55,8 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
override val isBypassEnabled: Flow<Boolean>
get() = emptyFlow()
override fun lockoutFaceAuth() = Unit
/**
* Trigger face authentication.
*

View File

@@ -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() {

View File

@@ -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()
)

View File

@@ -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")
}
}

View File

@@ -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()

View File

@@ -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()
}
}

View File

@@ -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