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 */ /** Whether bypass is currently enabled */
val isBypassEnabled: Flow<Boolean> val isBypassEnabled: Flow<Boolean>
/** Set whether face authentication should be locked out or not */
fun lockoutFaceAuth()
/** /**
* Trigger face authentication. * Trigger face authentication.
* *
@@ -199,6 +202,10 @@ constructor(
} }
?: flowOf(false) ?: flowOf(false)
override fun lockoutFaceAuth() {
_isLockedOut.value = true
}
private val faceLockoutResetCallback = private val faceLockoutResetCallback =
object : FaceManager.LockoutResetCallback() { object : FaceManager.LockoutResetCallback() {
override fun onLockoutReset(sensorId: Int) { override fun onLockoutReset(sensorId: Int) {
@@ -396,7 +403,7 @@ constructor(
private val faceAuthCallback = private val faceAuthCallback =
object : FaceManager.AuthenticationCallback() { object : FaceManager.AuthenticationCallback() {
override fun onAuthenticationFailed() { override fun onAuthenticationFailed() {
_authenticationStatus.value = FailedFaceAuthenticationStatus _authenticationStatus.value = FailedFaceAuthenticationStatus()
_isAuthenticated.value = false _isAuthenticated.value = false
faceAuthLogger.authenticationFailed() faceAuthLogger.authenticationFailed()
onFaceAuthRequestCompleted() onFaceAuthRequestCompleted()

View File

@@ -55,6 +55,8 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
override val isBypassEnabled: Flow<Boolean> override val isBypassEnabled: Flow<Boolean>
get() = emptyFlow() get() = emptyFlow()
override fun lockoutFaceAuth() = Unit
/** /**
* Trigger face authentication. * 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.FeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository 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.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState
@@ -67,6 +68,7 @@ constructor(
private val featureFlags: FeatureFlags, private val featureFlags: FeatureFlags,
private val faceAuthenticationLogger: FaceAuthenticationLogger, private val faceAuthenticationLogger: FaceAuthenticationLogger,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
) : CoreStartable, KeyguardFaceAuthInteractor { ) : CoreStartable, KeyguardFaceAuthInteractor {
private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
@@ -117,6 +119,15 @@ constructor(
) )
} }
.launchIn(applicationScope) .launchIn(applicationScope)
deviceEntryFingerprintAuthRepository.isLockedOut
.onEach {
if (it) {
faceAuthenticationLogger.faceLockedOut("Fingerprint locked out")
repository.lockoutFaceAuth()
}
}
.launchIn(applicationScope)
} }
override fun onSwipeUpOnBouncer() { override fun onSwipeUpOnBouncer() {

View File

@@ -23,29 +23,40 @@ import android.os.SystemClock.elapsedRealtime
* Authentication status provided by * Authentication status provided by
* [com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository] * [com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository]
*/ */
sealed class FaceAuthenticationStatus( sealed class FaceAuthenticationStatus
// present to break equality check if the same error occurs repeatedly.
val createdAt: Long = elapsedRealtime()
)
/** Success authentication status. */ /** Success authentication status. */
data class SuccessFaceAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) : data class SuccessFaceAuthenticationStatus(
FaceAuthenticationStatus() 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. */ /** Face authentication help message. */
data class HelpFaceAuthenticationStatus(val msgId: Int, val msg: String?) : data class HelpFaceAuthenticationStatus(
FaceAuthenticationStatus() 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. */ /** 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. */ /** 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 */ /** Face authentication error message */
data class ErrorFaceAuthenticationStatus( data class ErrorFaceAuthenticationStatus(
val msgId: Int, val msgId: Int,
val msg: String? = null, val msg: String? = null,
// present to break equality check if the same error occurs repeatedly.
@JvmField val createdAt: Long = elapsedRealtime()
) : FaceAuthenticationStatus() { ) : FaceAuthenticationStatus() {
/** /**
* Method that checks if [msgId] is a lockout error. A lockout error means that face * 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 userId: Int,
val isStrongBiometric: Boolean, val isStrongBiometric: Boolean,
// present to break equality check if the same error occurs repeatedly. // 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.keyguard.shared.model.TransitionStep
import com.android.systemui.log.core.LogLevel.DEBUG import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.FaceAuthLog import com.android.systemui.log.dagger.FaceAuthLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject import javax.inject.Inject
private const val TAG = "DeviceEntryFaceAuthRepositoryLog" private const val TAG = "DeviceEntryFaceAuthRepositoryLog"
@@ -264,4 +265,8 @@ constructor(
fun watchdogScheduled() { fun watchdogScheduled() {
logBuffer.log(TAG, DEBUG, "FaceManager Biometric watchdog scheduled.") 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() val successResult = successResult()
authenticationCallback.value.onAuthenticationSucceeded(successResult) authenticationCallback.value.onAuthenticationSucceeded(successResult)
assertThat(authStatus()).isEqualTo(SuccessFaceAuthenticationStatus(successResult)) val response = authStatus() as SuccessFaceAuthenticationStatus
assertThat(response.successResult).isEqualTo(successResult)
assertThat(authenticated()).isTrue() assertThat(authenticated()).isTrue()
assertThat(authRunning()).isFalse() assertThat(authRunning()).isFalse()
assertThat(canFaceAuthRun()).isFalse() assertThat(canFaceAuthRun()).isFalse()
@@ -494,7 +495,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
authenticationCallback.value.onAuthenticationHelp(10, "Ignored help msg") authenticationCallback.value.onAuthenticationHelp(10, "Ignored help msg")
authenticationCallback.value.onAuthenticationHelp(11, "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 @Test
@@ -550,10 +553,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
} }
@Test @Test
fun authenticateDoesNotRunWhenFpIsLockedOut() = fun authenticateDoesNotRunWhenFaceIsDisabled() =
testScope.runTest { testScope.runTest { testGatingCheckForFaceAuth { underTest.lockoutFaceAuth() } }
testGatingCheckForFaceAuth { deviceEntryFingerprintAuthRepository.setLockedOut(true) }
}
@Test @Test
fun authenticateDoesNotRunWhenUserIsCurrentlyTrusted() = 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 @Test
fun detectDoesNotRunWhenFaceAuthNotSupportedInCurrentPosture() = fun detectDoesNotRunWhenFaceAuthNotSupportedInCurrentPosture() =
testScope.runTest { testScope.runTest {
@@ -1070,10 +1084,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
} }
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() { private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() {
verify(faceManager, atLeastOnce())
.addLockoutResetCallback(faceLockoutResetCallback.capture())
biometricSettingsRepository.setFaceEnrolled(true) biometricSettingsRepository.setFaceEnrolled(true)
biometricSettingsRepository.setIsFaceAuthEnabled(true) biometricSettingsRepository.setIsFaceAuthEnabled(true)
fakeUserRepository.setUserSwitching(false) fakeUserRepository.setUserSwitching(false)
deviceEntryFingerprintAuthRepository.setLockedOut(false)
trustRepository.setCurrentUserTrusted(false) trustRepository.setCurrentUserTrusted(false)
keyguardRepository.setKeyguardGoingAway(false) keyguardRepository.setKeyguardGoingAway(false)
keyguardRepository.setWakefulnessModel( keyguardRepository.setWakefulnessModel(
@@ -1087,6 +1102,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
biometricSettingsRepository.setIsUserInLockdown(false) biometricSettingsRepository.setIsUserInLockdown(false)
fakeUserRepository.setSelectedUserInfo(primaryUser) fakeUserRepository.setSelectedUserInfo(primaryUser)
biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true) biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
faceLockoutResetCallback.value.onLockoutReset(0)
bouncerRepository.setAlternateVisible(true) bouncerRepository.setAlternateVisible(true)
keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardShowing(true)
runCurrent() runCurrent()

View File

@@ -38,6 +38,7 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository 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.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
@@ -73,6 +74,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository
private lateinit var fakeDeviceEntryFingerprintAuthRepository:
FakeDeviceEntryFingerprintAuthRepository
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@@ -94,6 +97,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
) )
.keyguardTransitionInteractor .keyguardTransitionInteractor
fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
underTest = underTest =
SystemUIKeyguardFaceAuthInteractor( SystemUIKeyguardFaceAuthInteractor(
mContext, mContext,
@@ -127,6 +131,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
featureFlags, featureFlags,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")), FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
keyguardUpdateMonitor, keyguardUpdateMonitor,
fakeDeviceEntryFingerprintAuthRepository
) )
} }
@@ -335,4 +340,14 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
assertThat(faceAuthRepository.runningAuthRequest.value) assertThat(faceAuthRepository.runningAuthRequest.value)
.isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER, false)) .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 { class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
private var _wasDisabled: Boolean = false
val wasDisabled: Boolean
get() = _wasDisabled
override val isAuthenticated = MutableStateFlow(false) override val isAuthenticated = MutableStateFlow(false)
override val canRunFaceAuth = MutableStateFlow(false) override val canRunFaceAuth = MutableStateFlow(false)
private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null) private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null)
@@ -52,6 +57,9 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
override val isBypassEnabled = MutableStateFlow(false) override val isBypassEnabled = MutableStateFlow(false)
override fun lockoutFaceAuth() {
_wasDisabled = true
}
override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) { override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {
_runningAuthRequest.value = uiEvent to fallbackToDetection _runningAuthRequest.value = uiEvent to fallbackToDetection