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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24141476

Change-Id: I0f112e51291a81e5173c181aa09ac3baf8987bce
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index d1f011e..bf1e75b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -102,6 +102,9 @@
     /** 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 @@
         }
             ?: flowOf(false)
 
+    override fun lockoutFaceAuth() {
+        _isLockedOut.value = true
+    }
+
     private val faceLockoutResetCallback =
         object : FaceManager.LockoutResetCallback() {
             override fun onLockoutReset(sensorId: Int) {
@@ -396,7 +403,7 @@
     private val faceAuthCallback =
         object : FaceManager.AuthenticationCallback() {
             override fun onAuthenticationFailed() {
-                _authenticationStatus.value = FailedFaceAuthenticationStatus
+                _authenticationStatus.value = FailedFaceAuthenticationStatus()
                 _isAuthenticated.value = false
                 faceAuthLogger.authenticationFailed()
                 onFaceAuthRequestCompleted()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
index 27e3a74..5ef9a9e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
@@ -55,6 +55,8 @@
     override val isBypassEnabled: Flow<Boolean>
         get() = emptyFlow()
 
+    override fun lockoutFaceAuth() = Unit
+
     /**
      * Trigger face authentication.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 2afe97d..8f4776f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -30,6 +30,7 @@
 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 @@
     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 @@
                 )
             }
             .launchIn(applicationScope)
+
+        deviceEntryFingerprintAuthRepository.isLockedOut
+            .onEach {
+                if (it) {
+                    faceAuthenticationLogger.faceLockedOut("Fingerprint locked out")
+                    repository.lockoutFaceAuth()
+                }
+            }
+            .launchIn(applicationScope)
     }
 
     override fun onSwipeUpOnBouncer() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
index d9792cf..3de3666 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
@@ -23,29 +23,40 @@
  * 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 @@
     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()
 )
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index 373f705..66067b1 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -8,6 +8,7 @@
 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 @@
     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")
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 8127ac6..b3f8000 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -265,7 +265,8 @@
             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 @@
             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 @@
         }
 
     @Test
-    fun authenticateDoesNotRunWhenFpIsLockedOut() =
-        testScope.runTest {
-            testGatingCheckForFaceAuth { deviceEntryFingerprintAuthRepository.setLockedOut(true) }
-        }
+    fun authenticateDoesNotRunWhenFaceIsDisabled() =
+        testScope.runTest { testGatingCheckForFaceAuth { underTest.lockoutFaceAuth() } }
 
     @Test
     fun authenticateDoesNotRunWhenUserIsCurrentlyTrusted() =
@@ -858,6 +859,19 @@
         }
 
     @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 {
             testGatingCheckForDetect {
@@ -1070,10 +1084,11 @@
     }
 
     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 @@
         biometricSettingsRepository.setIsUserInLockdown(false)
         fakeUserRepository.setSelectedUserInfo(primaryUser)
         biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
+        faceLockoutResetCallback.value.onLockoutReset(0)
         bouncerRepository.setAlternateVisible(true)
         keyguardRepository.setKeyguardShowing(true)
         runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index ced0a21..8c9ed5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -38,6 +38,7 @@
 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 @@
     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 @@
                 )
                 .keyguardTransitionInteractor
 
+        fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
         underTest =
             SystemUIKeyguardFaceAuthInteractor(
                 mContext,
@@ -127,6 +131,7 @@
                 featureFlags,
                 FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
                 keyguardUpdateMonitor,
+                fakeDeviceEntryFingerprintAuthRepository
             )
     }
 
@@ -335,4 +340,14 @@
             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()
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
index 548169e..f4c2db1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
@@ -27,6 +27,11 @@
 
 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 @@
     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