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 */
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.
*
@@ -186,6 +198,15 @@ constructor(
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 @@ constructor(
"isFaceAuthenticationEnabled",
tableLogBuffer
),
logAndObserve(
userRepository.userSwitchingInProgress.isFalse(),
"userSwitchingNotInProgress",
tableLogBuffer
),
logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
logAndObserve(
keyguardRepository.isKeyguardGoingAway.isFalse(),
"keyguardNotGoingAway",
@@ -454,7 +471,6 @@ constructor(
}
private fun handleFaceCancellationError() {
cancelNotReceivedHandlerJob?.cancel()
applicationScope.launch {
faceAuthRequestedWhileCancellation?.let {
faceAuthLogger.launchingQueuedFaceAuthRequest(it)
@@ -483,6 +499,7 @@ constructor(
}
private fun onFaceAuthRequestCompleted() {
cancelNotReceivedHandlerJob?.cancel()
cancellationInProgress = false
_isAuthRunning.value = false
authCancellationSignal = null

View File

@@ -56,6 +56,9 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
get() = emptyFlow()
override fun lockoutFaceAuth() = Unit
override fun pauseFaceAuth() = Unit
override fun resumeFaceAuth() = Unit
/**
* 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.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.map
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 @@ constructor(
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 @@ constructor(
}
}
.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 @@ constructor(
} 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 {

View File

@@ -541,10 +541,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
fun authenticateDoesNotRunIfUserIsCurrentlySwitching() =
testScope.runTest {
testGatingCheckForFaceAuth { fakeUserRepository.setUserSwitching(true) }
}
fun authenticateDoesNotRunIfFaceAuthIsCurrentlyPaused() =
testScope.runTest { testGatingCheckForFaceAuth { underTest.pauseFaceAuth() } }
@Test
fun authenticateDoesNotRunIfKeyguardIsNotShowing() =
@@ -840,7 +838,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
@Test
fun detectDoesNotRunWhenUserSwitchingInProgress() =
testScope.runTest { testGatingCheckForDetect { fakeUserRepository.setUserSwitching(true) } }
testScope.runTest { testGatingCheckForDetect { underTest.pauseFaceAuth() } }
@Test
fun detectDoesNotRunWhenKeyguardGoingAway() =
@@ -1130,7 +1128,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
.addLockoutResetCallback(faceLockoutResetCallback.capture())
biometricSettingsRepository.setFaceEnrolled(true)
biometricSettingsRepository.setIsFaceAuthEnabled(true)
fakeUserRepository.setUserSwitching(false)
underTest.resumeFaceAuth()
trustRepository.setCurrentUserTrusted(false)
keyguardRepository.setKeyguardGoingAway(false)
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.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 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
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 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
.keyguardTransitionInteractor
fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
fakeUserRepository = FakeUserRepository()
underTest =
SystemUIKeyguardFaceAuthInteractor(
mContext,
@@ -131,7 +134,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
featureFlags,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
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
fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() =
testScope.runTest {

View File

@@ -61,6 +61,19 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
_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