diff options
| author | 2023-08-23 19:41:53 +0000 | |
|---|---|---|
| committer | 2023-08-23 19:41:53 +0000 | |
| commit | eff111674be0f81a45cb52b853dbd918deb7d4bf (patch) | |
| tree | 892cbcbdd7275ef24bd7177f49a1095c469b220a | |
| parent | 0e42a651973b4ed78c644ec65fc4dc5571a3a136 (diff) | |
| parent | ab25d9379168bcc132592a8c38cb9695ddccaaac (diff) | |
Merge "Set the default state of canFaceAuth run to false." into main
11 files changed, 200 insertions, 122 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt index d2cb84945252..5b0bd959d902 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt @@ -20,7 +20,10 @@ package com.android.systemui.biometrics.data.repository import android.hardware.face.FaceManager import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.face.IFaceAuthenticatorsRegisteredCallback +import android.util.Log +import com.android.systemui.biometrics.shared.model.LockoutMode import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toLockoutMode import com.android.systemui.biometrics.shared.model.toSensorStrength import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow @@ -29,16 +32,18 @@ import com.android.systemui.dagger.qualifiers.Application import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.shareIn +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn /** A repository for the global state of Face sensor. */ interface FacePropertyRepository { /** Face sensor information, null if it is not available. */ - val sensorInfo: Flow<FaceSensorInfo?> + val sensorInfo: StateFlow<FaceSensorInfo?> + + /** Get the current lockout mode for the user. This makes a binder based service call. */ + suspend fun getLockoutMode(userId: Int): LockoutMode } /** Describes a biometric sensor */ @@ -49,33 +54,39 @@ private const val TAG = "FaceSensorPropertyRepositoryImpl" @SysUISingleton class FacePropertyRepositoryImpl @Inject -constructor(@Application private val applicationScope: CoroutineScope, faceManager: FaceManager?) : - FacePropertyRepository { +constructor( + @Application private val applicationScope: CoroutineScope, + private val faceManager: FaceManager? +) : FacePropertyRepository { - private val sensorProps: Flow<List<FaceSensorPropertiesInternal>> = - faceManager?.let { - ConflatedCallbackFlow.conflatedCallbackFlow { - val callback = - object : IFaceAuthenticatorsRegisteredCallback.Stub() { - override fun onAllAuthenticatorsRegistered( - sensors: List<FaceSensorPropertiesInternal> - ) { - trySendWithFailureLogging( - sensors, - TAG, - "onAllAuthenticatorsRegistered" - ) - } + override val sensorInfo: StateFlow<FaceSensorInfo?> = + ConflatedCallbackFlow.conflatedCallbackFlow { + val callback = + object : IFaceAuthenticatorsRegisteredCallback.Stub() { + override fun onAllAuthenticatorsRegistered( + sensors: List<FaceSensorPropertiesInternal>, + ) { + if (sensors.isEmpty()) return + trySendWithFailureLogging( + FaceSensorInfo( + sensors.first().sensorId, + sensors.first().sensorStrength.toSensorStrength() + ), + TAG, + "onAllAuthenticatorsRegistered" + ) } - it.addAuthenticatorsRegisteredCallback(callback) - awaitClose {} - } - .shareIn(applicationScope, SharingStarted.Eagerly) - } - ?: flowOf(emptyList()) + } + faceManager?.addAuthenticatorsRegisteredCallback(callback) + awaitClose {} + } + .onEach { Log.d(TAG, "sensorProps changed: $it") } + .stateIn(applicationScope, SharingStarted.Eagerly, null) - override val sensorInfo: Flow<FaceSensorInfo?> = - sensorProps - .map { it.firstOrNull() } - .map { it?.let { FaceSensorInfo(it.sensorId, it.sensorStrength.toSensorStrength()) } } + override suspend fun getLockoutMode(userId: Int): LockoutMode { + if (sensorInfo.value == null || faceManager == null) { + return LockoutMode.NONE + } + return faceManager.getLockoutModeForUser(sensorInfo.value!!.id, userId).toLockoutMode() + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt new file mode 100644 index 000000000000..68bba32537b0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.biometrics.shared.model + +import android.hardware.biometrics.BiometricConstants + +/** Lockout mode. Represents [BiometricConstants.LockoutMode]. */ +enum class LockoutMode { + NONE, + TIMED, + PERMANENT, +} + +/** Convert [this] to corresponding [LockoutMode] */ +fun Int.toLockoutMode(): LockoutMode = + when (this) { + BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT -> LockoutMode.PERMANENT + BiometricConstants.BIOMETRIC_LOCKOUT_TIMED -> LockoutMode.TIMED + else -> LockoutMode.NONE + } 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 93eb103d74e1..8064cc1cce88 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 @@ -52,6 +52,7 @@ import com.android.systemui.log.SessionTracker import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository import java.io.PrintWriter import java.util.Arrays @@ -71,6 +72,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge @@ -200,7 +202,7 @@ constructor( private val keyguardSessionId: InstanceId? get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD) - private val _canRunFaceAuth = MutableStateFlow(true) + private val _canRunFaceAuth = MutableStateFlow(false) override val canRunFaceAuth: StateFlow<Boolean> get() = _canRunFaceAuth @@ -281,7 +283,9 @@ constructor( } else { keyguardRepository.isKeyguardGoingAway }, - userRepository.userSwitchingInProgress, + userRepository.selectedUser.map { + it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS + }, ) .onEach { anyOfThemIsTrue -> if (anyOfThemIsTrue) { @@ -325,6 +329,7 @@ constructor( cancelDetection() } } + .flowOn(mainDispatcher) .logDiffsForTable(faceDetectLog, "", "canFaceDetectRun", false) .launchIn(applicationScope) } @@ -410,6 +415,7 @@ constructor( cancel() } } + .flowOn(mainDispatcher) .logDiffsForTable(faceAuthLog, "", "canFaceAuthRun", false) .launchIn(applicationScope) } 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 2a3f8520a63c..4b8171f60203 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 @@ -22,6 +22,8 @@ import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.CoreStartable import com.android.systemui.R +import com.android.systemui.biometrics.data.repository.FacePropertyRepository +import com.android.systemui.biometrics.shared.model.LockoutMode import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.dagger.SysUISingleton @@ -35,6 +37,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.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise import javax.inject.Inject @@ -51,6 +54,7 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlinx.coroutines.yield /** * Encapsulates business logic related face authentication being triggered for device entry from @@ -72,6 +76,7 @@ constructor( private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, private val userRepository: UserRepository, + private val facePropertyRepository: FacePropertyRepository, ) : CoreStartable, KeyguardFaceAuthInteractor { private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() @@ -92,7 +97,7 @@ constructor( faceAuthenticationLogger.bouncerVisibilityChanged() runFaceAuth( FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN, - fallbackToDetect = true + fallbackToDetect = false ) } .launchIn(applicationScope) @@ -134,16 +139,25 @@ constructor( // 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) -> + userRepository.selectedUser + .pairwise() + .onEach { (previous, curr) -> + val wasSwitching = previous.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS + val isSwitching = curr.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS if (!wasSwitching && isSwitching) { repository.pauseFaceAuth() } else if (wasSwitching && !isSwitching) { + val lockoutMode = facePropertyRepository.getLockoutMode(curr.userInfo.id) + if (lockoutMode == LockoutMode.PERMANENT || lockoutMode == LockoutMode.TIMED) { + repository.lockoutFaceAuth() + } repository.resumeFaceAuth() + yield() runFaceAuth( FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING, - fallbackToDetect = true + // Fallback to detection if bouncer is not showing so that we can detect a + // face and then show the bouncer to the user if face auth can't run + fallbackToDetect = !primaryBouncerInteractor.isBouncerShowing() ) } } diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt index 954765c4581d..8cfa55570723 100644 --- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt @@ -31,7 +31,6 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.settings.UserTracker import com.android.systemui.user.data.model.SelectedUserModel import com.android.systemui.user.data.model.SelectionStatus @@ -49,7 +48,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart @@ -77,9 +75,6 @@ interface UserRepository { /** [UserInfo] of the currently-selected user. */ val selectedUserInfo: Flow<UserInfo> - /** Whether user switching is currently in progress. */ - val userSwitchingInProgress: Flow<Boolean> - /** User ID of the main user. */ val mainUserId: Int @@ -162,10 +157,6 @@ constructor( private var _isGuestUserResetting: Boolean = false override var isGuestUserResetting: Boolean = _isGuestUserResetting - private val _isUserSwitchingInProgress = MutableStateFlow(false) - override val userSwitchingInProgress: Flow<Boolean> - get() = _isUserSwitchingInProgress - override val isGuestUserCreationScheduled = AtomicBoolean() override val isStatusBarUserChipEnabled: Boolean = @@ -175,12 +166,6 @@ constructor( override var isRefreshUsersPaused: Boolean = false - init { - if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) { - observeUserSwitching() - } - } - override val selectedUser: StateFlow<SelectedUserModel> = run { // Some callbacks don't modify the selection status, so maintain the current value. var currentSelectionStatus = SelectionStatus.SELECTION_COMPLETE @@ -259,28 +244,6 @@ constructor( return _userSwitcherSettings.value.isUserSwitcherEnabled } - private fun observeUserSwitching() { - conflatedCallbackFlow { - val callback = - object : UserTracker.Callback { - override fun onUserChanging(newUser: Int, userContext: Context) { - trySendWithFailureLogging(true, TAG, "userSwitching started") - } - - override fun onUserChanged(newUserId: Int, userContext: Context) { - trySendWithFailureLogging(false, TAG, "userSwitching completed") - } - } - tracker.addCallback(callback, mainDispatcher.asExecutor()) - trySendWithFailureLogging(false, TAG, "initial value defaulting to false") - awaitClose { tracker.removeCallback(callback) } - } - .onEach { _isUserSwitchingInProgress.value = it } - // TODO (b/262838215), Make this stateIn and initialize directly in field declaration - // once the flag is launched - .launchIn(applicationScope) - } - private suspend fun getSettings(): UserSwitcherSettingsModel { return withContext(backgroundDispatcher) { val isSimpleUserSwitcher = diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt index fcc40404bf7d..0da7b4ac88f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt @@ -17,14 +17,19 @@ package com.android.systemui.biometrics.data.repository +import android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE +import android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT +import android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED import android.hardware.biometrics.SensorProperties import android.hardware.face.FaceManager import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.face.IFaceAuthenticatorsRegisteredCallback import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.shared.model.LockoutMode import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -74,18 +79,52 @@ class FacePropertyRepositoryImplTest : SysuiTestCase() { @Test fun providesTheValuePassedToTheAuthenticatorsRegisteredCallback() { testScope.runTest { - val sensor by collectLastValue(underTest.sensorInfo) runCurrent() verify(faceManager).addAuthenticatorsRegisteredCallback(callback.capture()) callback.value.onAllAuthenticatorsRegistered( listOf(createSensorProperties(1, SensorProperties.STRENGTH_STRONG)) ) + runCurrent() + val sensor by collectLastValue(underTest.sensorInfo) assertThat(sensor).isEqualTo(FaceSensorInfo(1, SensorStrength.STRONG)) } } + @Test + fun providesTheNoneLockoutModeWhenFaceManagerIsNotAvailable() = + testScope.runTest { + underTest = createRepository(null) + + assertThat(underTest.getLockoutMode(-1)).isEqualTo(LockoutMode.NONE) + } + + @Test + fun providesTheLockoutModeFromFaceManager() = + testScope.runTest { + val sensorId = 99 + val userId = 999 + runCurrent() + verify(faceManager).addAuthenticatorsRegisteredCallback(callback.capture()) + callback.value.onAllAuthenticatorsRegistered( + listOf(createSensorProperties(sensorId, SensorProperties.STRENGTH_STRONG)) + ) + runCurrent() + + whenever(faceManager.getLockoutModeForUser(sensorId, userId)) + .thenReturn(BIOMETRIC_LOCKOUT_TIMED) + assertThat(underTest.getLockoutMode(userId)).isEqualTo(LockoutMode.TIMED) + + whenever(faceManager.getLockoutModeForUser(sensorId, userId)) + .thenReturn(BIOMETRIC_LOCKOUT_PERMANENT) + assertThat(underTest.getLockoutMode(userId)).isEqualTo(LockoutMode.PERMANENT) + + whenever(faceManager.getLockoutModeForUser(sensorId, userId)) + .thenReturn(BIOMETRIC_LOCKOUT_NONE) + assertThat(underTest.getLockoutMode(userId)).isEqualTo(LockoutMode.NONE) + } + private fun createSensorProperties(id: Int, strength: Int) = FaceSensorPropertiesInternal(id, strength, 0, emptyList(), 1, false, false, false) } 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 64b94707da57..f0dbaf1aeaf3 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 @@ -71,6 +71,7 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.FakeKeyguardStateController import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.KotlinArgumentCaptor import com.android.systemui.util.mockito.captureMany @@ -295,6 +296,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { fun faceAuthDoesNotRunWhileItIsAlreadyRunning() = testScope.runTest { initCollectors() + allPreconditionsToRunFaceAuthAreTrue() underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER) faceAuthenticateIsCalled() @@ -311,6 +313,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { testScope.runTest { initCollectors() verify(faceManager).addLockoutResetCallback(faceLockoutResetCallback.capture()) + allPreconditionsToRunFaceAuthAreTrue() underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER) faceAuthenticateIsCalled() @@ -364,6 +367,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { fun cancelStopsFaceAuthentication() = testScope.runTest { initCollectors() + allPreconditionsToRunFaceAuthAreTrue() underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER) faceAuthenticateIsCalled() @@ -417,6 +421,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { fun faceAuthShouldWaitAndRunIfTriggeredWhileCancelling() = testScope.runTest { initCollectors() + allPreconditionsToRunFaceAuthAreTrue() underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER) faceAuthenticateIsCalled() @@ -492,6 +497,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { ) underTest = createDeviceEntryFaceAuthRepositoryImpl() initCollectors() + allPreconditionsToRunFaceAuthAreTrue() underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER) faceAuthenticateIsCalled() @@ -803,7 +809,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { assertThat(authenticated()).isTrue() - fakeUserRepository.setUserSwitching(true) + fakeUserRepository.setSelectedUserInfo( + primaryUser, + SelectionStatus.SELECTION_IN_PROGRESS + ) assertThat(authenticated()).isFalse() } 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 93f208ee14f5..ec115738df8b 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 @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.domain.interactor +import android.content.pm.UserInfo import android.hardware.biometrics.BiometricFaceConstants import android.os.Handler import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -25,6 +26,8 @@ import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository +import com.android.systemui.biometrics.shared.model.LockoutMode import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor @@ -48,6 +51,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.model.SelectionStatus import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -76,6 +80,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository private lateinit var fakeUserRepository: FakeUserRepository + private lateinit var facePropertyRepository: FakeFacePropertyRepository private lateinit var fakeDeviceEntryFingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository @@ -101,6 +106,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() fakeUserRepository = FakeUserRepository() + fakeUserRepository.setUserInfos(listOf(primaryUser, secondaryUser)) + facePropertyRepository = FakeFacePropertyRepository() underTest = SystemUIKeyguardFaceAuthInteractor( mContext, @@ -136,6 +143,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { keyguardUpdateMonitor, fakeDeviceEntryFingerprintAuthRepository, fakeUserRepository, + facePropertyRepository, ) } @@ -220,9 +228,12 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { testScope.runTest { underTest.start() - fakeUserRepository.setUserSwitching(false) + fakeUserRepository.setSelectedUserInfo(primaryUser, SelectionStatus.SELECTION_COMPLETE) runCurrent() - fakeUserRepository.setUserSwitching(true) + fakeUserRepository.setSelectedUserInfo( + secondaryUser, + SelectionStatus.SELECTION_IN_PROGRESS + ) runCurrent() assertThat(faceAuthRepository.isFaceAuthPaused()).isTrue() @@ -234,17 +245,27 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { underTest.start() // previously running - fakeUserRepository.setUserSwitching(true) + fakeUserRepository.setSelectedUserInfo( + primaryUser, + SelectionStatus.SELECTION_IN_PROGRESS + ) runCurrent() - fakeUserRepository.setUserSwitching(false) + bouncerRepository.setPrimaryShow(true) + + facePropertyRepository.setLockoutMode(secondaryUser.id, LockoutMode.TIMED) + fakeUserRepository.setSelectedUserInfo( + secondaryUser, + SelectionStatus.SELECTION_COMPLETE + ) runCurrent() assertThat(faceAuthRepository.isFaceAuthPaused()).isFalse() + assertThat(faceAuthRepository.wasDisabled).isTrue() runCurrent() assertThat(faceAuthRepository.runningAuthRequest.value!!.first) .isEqualTo(FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING) - assertThat(faceAuthRepository.runningAuthRequest.value!!.second).isEqualTo(true) + assertThat(faceAuthRepository.runningAuthRequest.value!!.second).isEqualTo(false) } @Test @@ -259,7 +280,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { runCurrent() assertThat(faceAuthRepository.runningAuthRequest.value) - .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN, true)) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN, false)) } @Test @@ -387,4 +408,11 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { assertThat(faceAuthRepository.wasDisabled).isTrue() } + + companion object { + private const val primaryUserId = 1 + private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY) + + private val secondaryUser = UserInfo(2, "secondary user", 0) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt index 0c28cbb52831..e249cece5a1e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt @@ -259,35 +259,6 @@ class UserRepositoryImplTest : SysuiTestCase() { assertThat(selectedUser!!.selectionStatus).isEqualTo(SelectionStatus.SELECTION_IN_PROGRESS) } - @Test - fun userSwitchingInProgress_registersUserTrackerCallback() = runSelfCancelingTest { - underTest = create(this) - - underTest.userSwitchingInProgress.launchIn(this) - underTest.userSwitchingInProgress.launchIn(this) - underTest.userSwitchingInProgress.launchIn(this) - - // Two callbacks registered - one for observing user switching and one for observing the - // selected user - assertThat(tracker.callbacks.size).isEqualTo(2) - } - - @Test - fun userSwitchingInProgress_propagatesStateFromUserTracker() = runSelfCancelingTest { - underTest = create(this) - assertThat(tracker.callbacks.size).isEqualTo(2) - - tracker.onUserChanging(0) - - var mostRecentSwitchingValue = false - underTest.userSwitchingInProgress.onEach { mostRecentSwitchingValue = it }.launchIn(this) - - assertThat(mostRecentSwitchingValue).isTrue() - - tracker.onUserChanged(0) - assertThat(mostRecentSwitchingValue).isFalse() - } - private fun createUserInfo( id: Int, isGuest: Boolean, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt index 2ef1be70000f..51ce9f00a709 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt @@ -17,14 +17,24 @@ package com.android.systemui.biometrics.data.repository -import kotlinx.coroutines.flow.Flow +import com.android.systemui.biometrics.shared.model.LockoutMode import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow class FakeFacePropertyRepository : FacePropertyRepository { private val faceSensorInfo = MutableStateFlow<FaceSensorInfo?>(null) - override val sensorInfo: Flow<FaceSensorInfo?> + override val sensorInfo: StateFlow<FaceSensorInfo?> get() = faceSensorInfo + private val lockoutModesForUser = mutableMapOf<Int, LockoutMode>() + + fun setLockoutMode(userId: Int, mode: LockoutMode) { + lockoutModesForUser[userId] = mode + } + override suspend fun getLockoutMode(userId: Int): LockoutMode { + return lockoutModesForUser[userId]!! + } + fun setSensorInfo(value: FaceSensorInfo?) { faceSensorInfo.value = value } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt index 51ee0c00cb0d..5ad19eed18b8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt @@ -56,10 +56,6 @@ class FakeUserRepository : UserRepository { ) override val selectedUserInfo: Flow<UserInfo> = selectedUser.map { it.userInfo } - private val _userSwitchingInProgress = MutableStateFlow(false) - override val userSwitchingInProgress: Flow<Boolean> - get() = _userSwitchingInProgress - override var mainUserId: Int = MAIN_USER_ID override var lastSelectedNonGuestUserId: Int = mainUserId @@ -120,8 +116,4 @@ class FakeUserRepository : UserRepository { fun setGuestUserAutoCreated(value: Boolean) { _isGuestUserAutoCreated = value } - - fun setUserSwitching(value: Boolean) { - _userSwitchingInProgress.value = value - } } |