Merge "Minor cleanup: move logic that locks face whenever fingerprint is locked to the interactor" into udc-qpr-dev am: 3490e6fb8f
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24141476 Change-Id: Ib0d3609ccc07ce0376b5e167ca4d1fed910b03e4 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user