Merge "Trigger face auth whenever user switching has completed." into udc-qpr-dev
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 6fd3e21..30f8f3e 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
@@ -110,6 +110,18 @@
fun lockoutFaceAuth()
/**
+ * Cancel current face authentication and prevent it from running until [resumeFaceAuth] is
+ * invoked.
+ */
+ fun pauseFaceAuth()
+
+ /**
+ * Allow face auth paused using [pauseFaceAuth] to run again. The next invocation to
+ * [authenticate] will run as long as other gating conditions don't stop it from running.
+ */
+ fun resumeFaceAuth()
+
+ /**
* Trigger face authentication.
*
* [uiEvent] provided should be logged whenever face authentication runs. Invocation should be
@@ -186,6 +198,15 @@
override val isAuthRunning: StateFlow<Boolean>
get() = _isAuthRunning
+ private val faceAuthPaused = MutableStateFlow(false)
+ override fun pauseFaceAuth() {
+ faceAuthPaused.value = true
+ }
+
+ override fun resumeFaceAuth() {
+ faceAuthPaused.value = false
+ }
+
private val keyguardSessionId: InstanceId?
get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
@@ -329,11 +350,7 @@
"isFaceAuthenticationEnabled",
tableLogBuffer
),
- logAndObserve(
- userRepository.userSwitchingInProgress.isFalse(),
- "userSwitchingNotInProgress",
- tableLogBuffer
- ),
+ logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
logAndObserve(
keyguardRepository.isKeyguardGoingAway.isFalse(),
"keyguardNotGoingAway",
@@ -454,7 +471,6 @@
}
private fun handleFaceCancellationError() {
- cancelNotReceivedHandlerJob?.cancel()
applicationScope.launch {
faceAuthRequestedWhileCancellation?.let {
faceAuthLogger.launchingQueuedFaceAuthRequest(it)
@@ -483,6 +499,7 @@
}
private fun onFaceAuthRequestCompleted() {
+ cancelNotReceivedHandlerJob?.cancel()
cancellationInProgress = false
_isAuthRunning.value = false
authCancellationSignal = null
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 5ef9a9e..e4e6a6d 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
@@ -56,6 +56,9 @@
get() = emptyFlow()
override fun lockoutFaceAuth() = Unit
+ override fun pauseFaceAuth() = Unit
+
+ override fun resumeFaceAuth() = 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 8f4776f..2a3f852 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
@@ -35,6 +35,7 @@
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
+import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -49,6 +50,7 @@
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Encapsulates business logic related face authentication being triggered for device entry from
@@ -69,6 +71,7 @@
private val faceAuthenticationLogger: FaceAuthenticationLogger,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val userRepository: UserRepository,
) : CoreStartable, KeyguardFaceAuthInteractor {
private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
@@ -128,6 +131,23 @@
}
}
.launchIn(applicationScope)
+
+ // User switching should stop face auth and then when it is complete we should trigger face
+ // auth so that the switched user can unlock the device with face auth.
+ userRepository.userSwitchingInProgress
+ .pairwise(false)
+ .onEach { (wasSwitching, isSwitching) ->
+ if (!wasSwitching && isSwitching) {
+ repository.pauseFaceAuth()
+ } else if (wasSwitching && !isSwitching) {
+ repository.resumeFaceAuth()
+ runFaceAuth(
+ FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING,
+ fallbackToDetect = true
+ )
+ }
+ }
+ .launchIn(applicationScope)
}
override fun onSwipeUpOnBouncer() {
@@ -199,8 +219,10 @@
} else {
faceAuthenticationStatusOverride.value = null
applicationScope.launch {
- faceAuthenticationLogger.authRequested(uiEvent)
- repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
+ withContext(mainDispatcher) {
+ faceAuthenticationLogger.authRequested(uiEvent)
+ repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
+ }
}
}
} else {
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 01a6c64..85ee0e4 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
@@ -541,10 +541,8 @@
}
@Test
- fun authenticateDoesNotRunIfUserIsCurrentlySwitching() =
- testScope.runTest {
- testGatingCheckForFaceAuth { fakeUserRepository.setUserSwitching(true) }
- }
+ fun authenticateDoesNotRunIfFaceAuthIsCurrentlyPaused() =
+ testScope.runTest { testGatingCheckForFaceAuth { underTest.pauseFaceAuth() } }
@Test
fun authenticateDoesNotRunIfKeyguardIsNotShowing() =
@@ -840,7 +838,7 @@
@Test
fun detectDoesNotRunWhenUserSwitchingInProgress() =
- testScope.runTest { testGatingCheckForDetect { fakeUserRepository.setUserSwitching(true) } }
+ testScope.runTest { testGatingCheckForDetect { underTest.pauseFaceAuth() } }
@Test
fun detectDoesNotRunWhenKeyguardGoingAway() =
@@ -1130,7 +1128,7 @@
.addLockoutResetCallback(faceLockoutResetCallback.capture())
biometricSettingsRepository.setFaceEnrolled(true)
biometricSettingsRepository.setIsFaceAuthEnabled(true)
- fakeUserRepository.setUserSwitching(false)
+ underTest.resumeFaceAuth()
trustRepository.setCurrentUserTrusted(false)
keyguardRepository.setKeyguardGoingAway(false)
keyguardRepository.setWakefulnessModel(
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 8636dd8..93f208e 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
@@ -48,6 +48,7 @@
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -74,6 +75,7 @@
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository
+ private lateinit var fakeUserRepository: FakeUserRepository
private lateinit var fakeDeviceEntryFingerprintAuthRepository:
FakeDeviceEntryFingerprintAuthRepository
@@ -98,6 +100,7 @@
.keyguardTransitionInteractor
fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ fakeUserRepository = FakeUserRepository()
underTest =
SystemUIKeyguardFaceAuthInteractor(
mContext,
@@ -131,7 +134,8 @@
featureFlags,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
keyguardUpdateMonitor,
- fakeDeviceEntryFingerprintAuthRepository
+ fakeDeviceEntryFingerprintAuthRepository,
+ fakeUserRepository,
)
}
@@ -212,6 +216,38 @@
}
@Test
+ fun faceAuthIsPausedWhenUserSwitchingIsInProgress() =
+ testScope.runTest {
+ underTest.start()
+
+ fakeUserRepository.setUserSwitching(false)
+ runCurrent()
+ fakeUserRepository.setUserSwitching(true)
+ runCurrent()
+
+ assertThat(faceAuthRepository.isFaceAuthPaused()).isTrue()
+ }
+
+ @Test
+ fun faceAuthIsUnpausedWhenUserSwitchingIsInComplete() =
+ testScope.runTest {
+ underTest.start()
+
+ // previously running
+ fakeUserRepository.setUserSwitching(true)
+ runCurrent()
+ fakeUserRepository.setUserSwitching(false)
+ runCurrent()
+
+ assertThat(faceAuthRepository.isFaceAuthPaused()).isFalse()
+
+ runCurrent()
+ assertThat(faceAuthRepository.runningAuthRequest.value!!.first)
+ .isEqualTo(FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING)
+ assertThat(faceAuthRepository.runningAuthRequest.value!!.second).isEqualTo(true)
+ }
+
+ @Test
fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() =
testScope.runTest {
underTest.start()
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 f4c2db1..1e1dc4f 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
@@ -61,6 +61,19 @@
_wasDisabled = true
}
+ private val faceAuthPaused = MutableStateFlow(false)
+ override fun pauseFaceAuth() {
+ faceAuthPaused.value = true
+ }
+
+ override fun resumeFaceAuth() {
+ faceAuthPaused.value = false
+ }
+
+ fun isFaceAuthPaused(): Boolean {
+ return faceAuthPaused.value
+ }
+
override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {
_runningAuthRequest.value = uiEvent to fallbackToDetection
_isAuthRunning.value = true