Merge "Trigger face auth whenever user switching has completed." into udc-qpr-dev

This commit is contained in:
Chandru S
2023-07-28 20:37:33 +00:00
committed by Android (Google) Code Review
6 changed files with 104 additions and 15 deletions

View File

@@ -109,6 +109,18 @@ interface DeviceEntryFaceAuthRepository {
/** Set whether face authentication should be locked out or not */ /** Set whether face authentication should be locked out or not */
fun lockoutFaceAuth() 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. * Trigger face authentication.
* *
@@ -186,6 +198,15 @@ constructor(
override val isAuthRunning: StateFlow<Boolean> override val isAuthRunning: StateFlow<Boolean>
get() = _isAuthRunning get() = _isAuthRunning
private val faceAuthPaused = MutableStateFlow(false)
override fun pauseFaceAuth() {
faceAuthPaused.value = true
}
override fun resumeFaceAuth() {
faceAuthPaused.value = false
}
private val keyguardSessionId: InstanceId? private val keyguardSessionId: InstanceId?
get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD) get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
@@ -329,11 +350,7 @@ constructor(
"isFaceAuthenticationEnabled", "isFaceAuthenticationEnabled",
tableLogBuffer tableLogBuffer
), ),
logAndObserve( logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
userRepository.userSwitchingInProgress.isFalse(),
"userSwitchingNotInProgress",
tableLogBuffer
),
logAndObserve( logAndObserve(
keyguardRepository.isKeyguardGoingAway.isFalse(), keyguardRepository.isKeyguardGoingAway.isFalse(),
"keyguardNotGoingAway", "keyguardNotGoingAway",
@@ -454,7 +471,6 @@ constructor(
} }
private fun handleFaceCancellationError() { private fun handleFaceCancellationError() {
cancelNotReceivedHandlerJob?.cancel()
applicationScope.launch { applicationScope.launch {
faceAuthRequestedWhileCancellation?.let { faceAuthRequestedWhileCancellation?.let {
faceAuthLogger.launchingQueuedFaceAuthRequest(it) faceAuthLogger.launchingQueuedFaceAuthRequest(it)
@@ -483,6 +499,7 @@ constructor(
} }
private fun onFaceAuthRequestCompleted() { private fun onFaceAuthRequestCompleted() {
cancelNotReceivedHandlerJob?.cancel()
cancellationInProgress = false cancellationInProgress = false
_isAuthRunning.value = false _isAuthRunning.value = false
authCancellationSignal = null authCancellationSignal = null

View File

@@ -56,6 +56,9 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
get() = emptyFlow() get() = emptyFlow()
override fun lockoutFaceAuth() = Unit override fun lockoutFaceAuth() = Unit
override fun pauseFaceAuth() = Unit
override fun resumeFaceAuth() = Unit
/** /**
* Trigger face authentication. * Trigger face authentication.

View File

@@ -35,6 +35,7 @@ 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
import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
@@ -49,6 +50,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/** /**
* Encapsulates business logic related face authentication being triggered for device entry from * Encapsulates business logic related face authentication being triggered for device entry from
@@ -69,6 +71,7 @@ constructor(
private val faceAuthenticationLogger: FaceAuthenticationLogger, private val faceAuthenticationLogger: FaceAuthenticationLogger,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
private val userRepository: UserRepository,
) : CoreStartable, KeyguardFaceAuthInteractor { ) : CoreStartable, KeyguardFaceAuthInteractor {
private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
@@ -128,6 +131,23 @@ constructor(
} }
} }
.launchIn(applicationScope) .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() { override fun onSwipeUpOnBouncer() {
@@ -199,8 +219,10 @@ constructor(
} else { } else {
faceAuthenticationStatusOverride.value = null faceAuthenticationStatusOverride.value = null
applicationScope.launch { applicationScope.launch {
faceAuthenticationLogger.authRequested(uiEvent) withContext(mainDispatcher) {
repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect) faceAuthenticationLogger.authRequested(uiEvent)
repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
}
} }
} }
} else { } else {

View File

@@ -541,10 +541,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
} }
@Test @Test
fun authenticateDoesNotRunIfUserIsCurrentlySwitching() = fun authenticateDoesNotRunIfFaceAuthIsCurrentlyPaused() =
testScope.runTest { testScope.runTest { testGatingCheckForFaceAuth { underTest.pauseFaceAuth() } }
testGatingCheckForFaceAuth { fakeUserRepository.setUserSwitching(true) }
}
@Test @Test
fun authenticateDoesNotRunIfKeyguardIsNotShowing() = fun authenticateDoesNotRunIfKeyguardIsNotShowing() =
@@ -840,7 +838,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
@Test @Test
fun detectDoesNotRunWhenUserSwitchingInProgress() = fun detectDoesNotRunWhenUserSwitchingInProgress() =
testScope.runTest { testGatingCheckForDetect { fakeUserRepository.setUserSwitching(true) } } testScope.runTest { testGatingCheckForDetect { underTest.pauseFaceAuth() } }
@Test @Test
fun detectDoesNotRunWhenKeyguardGoingAway() = fun detectDoesNotRunWhenKeyguardGoingAway() =
@@ -1130,7 +1128,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
.addLockoutResetCallback(faceLockoutResetCallback.capture()) .addLockoutResetCallback(faceLockoutResetCallback.capture())
biometricSettingsRepository.setFaceEnrolled(true) biometricSettingsRepository.setFaceEnrolled(true)
biometricSettingsRepository.setIsFaceAuthEnabled(true) biometricSettingsRepository.setIsFaceAuthEnabled(true)
fakeUserRepository.setUserSwitching(false) underTest.resumeFaceAuth()
trustRepository.setCurrentUserTrusted(false) trustRepository.setCurrentUserTrusted(false)
keyguardRepository.setKeyguardGoingAway(false) keyguardRepository.setKeyguardGoingAway(false)
keyguardRepository.setWakefulnessModel( keyguardRepository.setWakefulnessModel(

View File

@@ -48,6 +48,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -74,6 +75,7 @@ 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 fakeUserRepository: FakeUserRepository
private lateinit var fakeDeviceEntryFingerprintAuthRepository: private lateinit var fakeDeviceEntryFingerprintAuthRepository:
FakeDeviceEntryFingerprintAuthRepository FakeDeviceEntryFingerprintAuthRepository
@@ -98,6 +100,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
.keyguardTransitionInteractor .keyguardTransitionInteractor
fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
fakeUserRepository = FakeUserRepository()
underTest = underTest =
SystemUIKeyguardFaceAuthInteractor( SystemUIKeyguardFaceAuthInteractor(
mContext, mContext,
@@ -131,7 +134,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
featureFlags, featureFlags,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")), FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
keyguardUpdateMonitor, keyguardUpdateMonitor,
fakeDeviceEntryFingerprintAuthRepository fakeDeviceEntryFingerprintAuthRepository,
fakeUserRepository,
) )
} }
@@ -211,6 +215,38 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
) )
} }
@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 @Test
fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() = fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() =
testScope.runTest { testScope.runTest {

View File

@@ -61,6 +61,19 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
_wasDisabled = true _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) { override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {
_runningAuthRequest.value = uiEvent to fallbackToDetection _runningAuthRequest.value = uiEvent to fallbackToDetection
_isAuthRunning.value = true _isAuthRunning.value = true