Merge "Trigger face auth whenever user switching has completed." into udc-qpr-dev
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user