Merge "Provide better API methods that can provide face/fp auth status" into udc-qpr-dev
This commit is contained in:
@@ -36,7 +36,6 @@ import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINL
|
||||
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
|
||||
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
|
||||
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.R.string.bouncer_face_not_recognized
|
||||
import com.android.systemui.R.string.keyguard_enter_password
|
||||
import com.android.systemui.R.string.keyguard_enter_pattern
|
||||
@@ -80,13 +79,14 @@ import com.android.systemui.R.string.kg_wrong_pin_try_again
|
||||
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
|
||||
import com.android.systemui.bouncer.shared.model.Message
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
@SysUISingleton
|
||||
class BouncerMessageFactory
|
||||
@Inject
|
||||
constructor(
|
||||
private val updateMonitor: KeyguardUpdateMonitor,
|
||||
private val biometricSettingsRepository: BiometricSettingsRepository,
|
||||
private val securityModel: KeyguardSecurityModel,
|
||||
) {
|
||||
|
||||
@@ -99,7 +99,7 @@ constructor(
|
||||
getBouncerMessage(
|
||||
reason,
|
||||
securityModel.getSecurityMode(userId),
|
||||
updateMonitor.isUnlockingWithFingerprintAllowed
|
||||
biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value
|
||||
)
|
||||
return pair?.let {
|
||||
BouncerMessageModel(
|
||||
|
||||
@@ -123,20 +123,11 @@ constructor(
|
||||
fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
|
||||
) : BouncerMessageRepository {
|
||||
|
||||
private val isFaceEnrolledAndEnabled =
|
||||
and(
|
||||
biometricSettingsRepository.isFaceAuthenticationEnabled,
|
||||
biometricSettingsRepository.isFaceEnrolled
|
||||
)
|
||||
|
||||
private val isFingerprintEnrolledAndEnabled =
|
||||
and(
|
||||
biometricSettingsRepository.isFingerprintEnabledByDevicePolicy,
|
||||
biometricSettingsRepository.isFingerprintEnrolled
|
||||
)
|
||||
|
||||
private val isAnyBiometricsEnabledAndEnrolled =
|
||||
or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled)
|
||||
or(
|
||||
biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
|
||||
biometricSettingsRepository.isFingerprintEnrolledAndEnabled,
|
||||
)
|
||||
|
||||
private val wasRebootedForMainlineUpdate
|
||||
get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
|
||||
@@ -335,8 +326,5 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun and(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
|
||||
flow.combine(anotherFlow) { a, b -> a && b }
|
||||
|
||||
private fun or(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
|
||||
flow.combine(anotherFlow) { a, b -> a || b }
|
||||
|
||||
@@ -83,9 +83,7 @@ constructor(
|
||||
|
||||
fun canShowAlternateBouncerForFingerprint(): Boolean {
|
||||
return bouncerRepository.alternateBouncerUIAvailable.value &&
|
||||
biometricSettingsRepository.isFingerprintEnrolled.value &&
|
||||
biometricSettingsRepository.isStrongBiometricAllowed.value &&
|
||||
biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
|
||||
biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value &&
|
||||
!keyguardUpdateMonitor.isFingerprintLockedOut &&
|
||||
!keyguardStateController.isUnlocked &&
|
||||
!statusBarStateController.isDozing
|
||||
|
||||
@@ -28,6 +28,9 @@ import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.biometrics.AuthController
|
||||
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
|
||||
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
@@ -68,34 +71,32 @@ import kotlinx.coroutines.flow.transformLatest
|
||||
* upstream changes.
|
||||
*/
|
||||
interface BiometricSettingsRepository {
|
||||
/** Whether any fingerprints are enrolled for the current user. */
|
||||
val isFingerprintEnrolled: StateFlow<Boolean>
|
||||
|
||||
/** Whether face authentication is enrolled for the current user. */
|
||||
val isFaceEnrolled: Flow<Boolean>
|
||||
/**
|
||||
* If the current user can enter the device using fingerprint. This is true if user has enrolled
|
||||
* fingerprints and fingerprint auth is not disabled through settings/device policy
|
||||
*/
|
||||
val isFingerprintEnrolledAndEnabled: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Whether face authentication is enabled/disabled based on system settings like device policy,
|
||||
* biometrics setting.
|
||||
* If the current user can enter the device using fingerprint, right now.
|
||||
*
|
||||
* This returns true if there are no strong auth flags that restrict the user from using
|
||||
* fingerprint and [isFingerprintEnrolledAndEnabled] is true
|
||||
*/
|
||||
val isFaceAuthenticationEnabled: Flow<Boolean>
|
||||
val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Whether the current user is allowed to use a strong biometric for device entry based on
|
||||
* Android Security policies. If false, the user may be able to use primary authentication for
|
||||
* device entry.
|
||||
* If the current user can use face auth to enter the device. This is true when the user has
|
||||
* face auth enrolled, and is enabled in settings/device policy.
|
||||
*/
|
||||
val isStrongBiometricAllowed: StateFlow<Boolean>
|
||||
val isFaceAuthEnrolledAndEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Whether the current user is allowed to use a convenience biometric for device entry based on
|
||||
* Android Security policies. If false, the user may be able to use strong biometric or primary
|
||||
* authentication for device entry.
|
||||
* If the current user can use face auth to enter the device right now. This is true when
|
||||
* [isFaceAuthEnrolledAndEnabled] is true and strong auth settings allow face auth to run and
|
||||
* face auth is supported by the current device posture.
|
||||
*/
|
||||
val isNonStrongBiometricAllowed: StateFlow<Boolean>
|
||||
|
||||
/** Whether fingerprint feature is enabled for the current user by the DevicePolicy */
|
||||
val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean>
|
||||
val isFaceAuthCurrentlyAllowed: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Whether face authentication is supported for the current device posture. Face auth can be
|
||||
@@ -130,6 +131,8 @@ constructor(
|
||||
@Background backgroundDispatcher: CoroutineDispatcher,
|
||||
biometricManager: BiometricManager?,
|
||||
devicePostureRepository: DevicePostureRepository,
|
||||
facePropertyRepository: FacePropertyRepository,
|
||||
fingerprintPropertyRepository: FingerprintPropertyRepository,
|
||||
dumpManager: DumpManager,
|
||||
) : BiometricSettingsRepository, Dumpable {
|
||||
|
||||
@@ -165,7 +168,9 @@ constructor(
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<String?>) {
|
||||
pw.println("isFingerprintEnrolled=${isFingerprintEnrolled.value}")
|
||||
pw.println("isFingerprintEnrolledAndEnabled=${isFingerprintEnrolledAndEnabled.value}")
|
||||
pw.println("isFingerprintAuthCurrentlyAllowed=${isFingerprintAuthCurrentlyAllowed.value}")
|
||||
pw.println("isNonStrongBiometricAllowed=${isNonStrongBiometricAllowed.value}")
|
||||
pw.println("isStrongBiometricAllowed=${isStrongBiometricAllowed.value}")
|
||||
pw.println("isFingerprintEnabledByDevicePolicy=${isFingerprintEnabledByDevicePolicy.value}")
|
||||
}
|
||||
@@ -180,7 +185,7 @@ constructor(
|
||||
user = UserHandle.ALL
|
||||
)
|
||||
|
||||
override val isFingerprintEnrolled: StateFlow<Boolean> =
|
||||
private val isFingerprintEnrolled: Flow<Boolean> =
|
||||
selectedUserId
|
||||
.flatMapLatest { currentUserId ->
|
||||
conflatedCallbackFlow {
|
||||
@@ -211,7 +216,7 @@ constructor(
|
||||
authController.isFingerprintEnrolled(userRepository.getSelectedUserInfo().id)
|
||||
)
|
||||
|
||||
override val isFaceEnrolled: Flow<Boolean> =
|
||||
private val isFaceEnrolled: Flow<Boolean> =
|
||||
selectedUserId.flatMapLatest { selectedUserId: Int ->
|
||||
conflatedCallbackFlow {
|
||||
val callback =
|
||||
@@ -245,14 +250,6 @@ constructor(
|
||||
isFaceEnabledByBiometricsManager.map { biometricsEnabledForUser[userInfo.id] ?: false }
|
||||
}
|
||||
|
||||
override val isFaceAuthenticationEnabled: Flow<Boolean>
|
||||
get() =
|
||||
combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) {
|
||||
biometricsManagerSetting,
|
||||
devicePolicySetting ->
|
||||
biometricsManagerSetting && devicePolicySetting
|
||||
}
|
||||
|
||||
private val isFaceEnabledByDevicePolicy: Flow<Boolean> =
|
||||
combine(selectedUserId, devicePolicyChangedForAllUsers) { userId, _ ->
|
||||
devicePolicyManager.isFaceDisabled(userId)
|
||||
@@ -263,6 +260,13 @@ constructor(
|
||||
.flowOn(backgroundDispatcher)
|
||||
.distinctUntilChanged()
|
||||
|
||||
private val isFaceAuthenticationEnabled: Flow<Boolean> =
|
||||
combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) {
|
||||
biometricsManagerSetting,
|
||||
devicePolicySetting ->
|
||||
biometricsManagerSetting && devicePolicySetting
|
||||
}
|
||||
|
||||
private val isFaceEnabledByBiometricsManager: Flow<Pair<Int, Boolean>> =
|
||||
conflatedCallbackFlow {
|
||||
val callback =
|
||||
@@ -283,7 +287,7 @@ constructor(
|
||||
// being registered.
|
||||
.stateIn(scope, SharingStarted.Eagerly, Pair(0, false))
|
||||
|
||||
override val isStrongBiometricAllowed: StateFlow<Boolean> =
|
||||
private val isStrongBiometricAllowed: StateFlow<Boolean> =
|
||||
strongAuthTracker.isStrongBiometricAllowed.stateIn(
|
||||
scope,
|
||||
SharingStarted.Eagerly,
|
||||
@@ -293,7 +297,7 @@ constructor(
|
||||
)
|
||||
)
|
||||
|
||||
override val isNonStrongBiometricAllowed: StateFlow<Boolean> =
|
||||
private val isNonStrongBiometricAllowed: StateFlow<Boolean> =
|
||||
strongAuthTracker.isNonStrongBiometricAllowed.stateIn(
|
||||
scope,
|
||||
SharingStarted.Eagerly,
|
||||
@@ -303,7 +307,19 @@ constructor(
|
||||
)
|
||||
)
|
||||
|
||||
override val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> =
|
||||
private val isFingerprintBiometricAllowed: Flow<Boolean> =
|
||||
fingerprintPropertyRepository.strength.flatMapLatest {
|
||||
if (it == SensorStrength.STRONG) isStrongBiometricAllowed
|
||||
else isNonStrongBiometricAllowed
|
||||
}
|
||||
|
||||
private val isFaceBiometricsAllowed: Flow<Boolean> =
|
||||
facePropertyRepository.sensorInfo.flatMapLatest {
|
||||
if (it?.strength == SensorStrength.STRONG) isStrongBiometricAllowed
|
||||
else isNonStrongBiometricAllowed
|
||||
}
|
||||
|
||||
private val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> =
|
||||
selectedUserId
|
||||
.flatMapLatest { userId ->
|
||||
devicePolicyChangedForAllUsers
|
||||
@@ -319,6 +335,25 @@ constructor(
|
||||
userRepository.getSelectedUserInfo().id
|
||||
)
|
||||
)
|
||||
|
||||
override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean> =
|
||||
isFingerprintEnrolled
|
||||
.and(isFingerprintEnabledByDevicePolicy)
|
||||
.stateIn(scope, SharingStarted.Eagerly, false)
|
||||
|
||||
override val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean> =
|
||||
isFingerprintEnrolledAndEnabled
|
||||
.and(isFingerprintBiometricAllowed)
|
||||
.stateIn(scope, SharingStarted.Eagerly, false)
|
||||
|
||||
override val isFaceAuthEnrolledAndEnabled: Flow<Boolean>
|
||||
get() = isFaceAuthenticationEnabled.and(isFaceEnrolled)
|
||||
|
||||
override val isFaceAuthCurrentlyAllowed: Flow<Boolean>
|
||||
get() =
|
||||
isFaceAuthEnrolledAndEnabled
|
||||
.and(isFaceBiometricsAllowed)
|
||||
.and(isFaceAuthSupportedInCurrentPosture)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
||||
@@ -26,8 +26,6 @@ import com.android.internal.logging.UiEventLogger
|
||||
import com.android.keyguard.FaceAuthUiEvent
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
||||
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
@@ -72,7 +70,6 @@ import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -162,7 +159,6 @@ constructor(
|
||||
@FaceAuthTableLog private val faceAuthLog: TableLogBuffer,
|
||||
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||
private val featureFlags: FeatureFlags,
|
||||
facePropertyRepository: FacePropertyRepository,
|
||||
dumpManager: DumpManager,
|
||||
) : DeviceEntryFaceAuthRepository, Dumpable {
|
||||
private var authCancellationSignal: CancellationSignal? = null
|
||||
@@ -182,13 +178,6 @@ constructor(
|
||||
override val detectionStatus: Flow<FaceDetectionStatus>
|
||||
get() = _detectionStatus.filterNotNull()
|
||||
|
||||
private val isFaceBiometricsAllowed: Flow<Boolean> =
|
||||
facePropertyRepository.sensorInfo.flatMapLatest {
|
||||
if (it?.strength == SensorStrength.STRONG)
|
||||
biometricSettingsRepository.isStrongBiometricAllowed
|
||||
else biometricSettingsRepository.isNonStrongBiometricAllowed
|
||||
}
|
||||
|
||||
private val _isLockedOut = MutableStateFlow(false)
|
||||
override val isLockedOut: StateFlow<Boolean> = _isLockedOut
|
||||
|
||||
@@ -313,8 +302,10 @@ constructor(
|
||||
canFaceAuthOrDetectRun(faceDetectLog),
|
||||
logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog),
|
||||
logAndObserve(
|
||||
isFaceBiometricsAllowed.isFalse().or(trustRepository.isCurrentUserTrusted),
|
||||
"biometricIsNotAllowedOrCurrentUserIsTrusted",
|
||||
biometricSettingsRepository.isFaceAuthCurrentlyAllowed
|
||||
.isFalse()
|
||||
.or(trustRepository.isCurrentUserTrusted),
|
||||
"faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted",
|
||||
faceDetectLog
|
||||
),
|
||||
// We don't want to run face detect if fingerprint can be used to unlock the device
|
||||
@@ -346,13 +337,8 @@ constructor(
|
||||
private fun canFaceAuthOrDetectRun(tableLogBuffer: TableLogBuffer): Flow<Boolean> {
|
||||
return listOf(
|
||||
logAndObserve(
|
||||
biometricSettingsRepository.isFaceEnrolled,
|
||||
"isFaceEnrolled",
|
||||
tableLogBuffer
|
||||
),
|
||||
logAndObserve(
|
||||
biometricSettingsRepository.isFaceAuthenticationEnabled,
|
||||
"isFaceAuthenticationEnabled",
|
||||
biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
|
||||
"isFaceAuthEnrolledAndEnabled",
|
||||
tableLogBuffer
|
||||
),
|
||||
logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
|
||||
@@ -406,7 +392,11 @@ constructor(
|
||||
"currentUserIsNotTrusted",
|
||||
faceAuthLog
|
||||
),
|
||||
logAndObserve(isFaceBiometricsAllowed, "isFaceBiometricsAllowed", faceAuthLog),
|
||||
logAndObserve(
|
||||
biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
|
||||
"isFaceAuthCurrentlyAllowed",
|
||||
faceAuthLog
|
||||
),
|
||||
logAndObserve(isAuthenticated.isFalse(), "faceNotAuthenticated", faceAuthLog),
|
||||
)
|
||||
.reduce(::and)
|
||||
|
||||
@@ -24,13 +24,12 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Pattern
|
||||
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
|
||||
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
|
||||
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.StringSubject
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
@@ -39,13 +38,12 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BouncerMessageFactoryTest : SysuiTestCase() {
|
||||
private lateinit var underTest: BouncerMessageFactory
|
||||
|
||||
@Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
|
||||
@Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
|
||||
|
||||
@Mock private lateinit var securityModel: KeyguardSecurityModel
|
||||
|
||||
@@ -55,7 +53,8 @@ class BouncerMessageFactoryTest : SysuiTestCase() {
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
testScope = TestScope()
|
||||
underTest = BouncerMessageFactory(updateMonitor, securityModel)
|
||||
biometricSettingsRepository = FakeBiometricSettingsRepository()
|
||||
underTest = BouncerMessageFactory(biometricSettingsRepository, securityModel)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,7 +166,7 @@ class BouncerMessageFactoryTest : SysuiTestCase() {
|
||||
secondaryMessageOverride: String? = null,
|
||||
): BouncerMessageModel? {
|
||||
whenever(securityModel.getSecurityMode(0)).thenReturn(mode)
|
||||
whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(fpAuthAllowed)
|
||||
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(fpAuthAllowed)
|
||||
|
||||
return underTest.createFromPromptReason(
|
||||
reason,
|
||||
|
||||
@@ -101,14 +101,15 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
|
||||
fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository()
|
||||
testScope = TestScope()
|
||||
|
||||
whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
|
||||
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
|
||||
underTest =
|
||||
BouncerMessageRepositoryImpl(
|
||||
trustRepository = trustRepository,
|
||||
biometricSettingsRepository = biometricSettingsRepository,
|
||||
updateMonitor = updateMonitor,
|
||||
bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel),
|
||||
bouncerMessageFactory =
|
||||
BouncerMessageFactory(biometricSettingsRepository, securityModel),
|
||||
userRepository = userRepository,
|
||||
fingerprintAuthRepository = fingerprintRepository,
|
||||
systemPropertiesHelper = systemPropertiesHelper
|
||||
@@ -222,8 +223,7 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
|
||||
whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
|
||||
.thenReturn("reboot,mainline_update")
|
||||
userRepository.setSelectedUserInfo(PRIMARY_USER)
|
||||
biometricSettingsRepository.setFaceEnrolled(true)
|
||||
biometricSettingsRepository.setIsFaceAuthEnabled(true)
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
|
||||
|
||||
verifyMessagesForAuthFlag(
|
||||
STRONG_AUTH_REQUIRED_AFTER_BOOT to
|
||||
@@ -236,8 +236,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
userRepository.setSelectedUserInfo(PRIMARY_USER)
|
||||
trustRepository.setCurrentUserTrustManaged(false)
|
||||
biometricSettingsRepository.setFaceEnrolled(false)
|
||||
biometricSettingsRepository.setFingerprintEnrolled(false)
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
|
||||
|
||||
verifyMessagesForAuthFlag(
|
||||
STRONG_AUTH_NOT_REQUIRED to null,
|
||||
@@ -258,8 +258,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
|
||||
fun authFlagsChanges_withTrustManaged_providesDifferentMessages() =
|
||||
testScope.runTest {
|
||||
userRepository.setSelectedUserInfo(PRIMARY_USER)
|
||||
biometricSettingsRepository.setFaceEnrolled(false)
|
||||
biometricSettingsRepository.setFingerprintEnrolled(false)
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
|
||||
|
||||
trustRepository.setCurrentUserTrustManaged(true)
|
||||
|
||||
@@ -290,10 +290,9 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
userRepository.setSelectedUserInfo(PRIMARY_USER)
|
||||
trustRepository.setCurrentUserTrustManaged(false)
|
||||
biometricSettingsRepository.setFingerprintEnrolled(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
|
||||
|
||||
biometricSettingsRepository.setIsFaceAuthEnabled(true)
|
||||
biometricSettingsRepository.setFaceEnrolled(true)
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
|
||||
|
||||
verifyMessagesForAuthFlag(
|
||||
STRONG_AUTH_NOT_REQUIRED to null,
|
||||
@@ -320,11 +319,9 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
userRepository.setSelectedUserInfo(PRIMARY_USER)
|
||||
trustRepository.setCurrentUserTrustManaged(false)
|
||||
biometricSettingsRepository.setIsFaceAuthEnabled(false)
|
||||
biometricSettingsRepository.setFaceEnrolled(false)
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
|
||||
|
||||
biometricSettingsRepository.setFingerprintEnrolled(true)
|
||||
biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
|
||||
|
||||
verifyMessagesForAuthFlag(
|
||||
STRONG_AUTH_NOT_REQUIRED to null,
|
||||
|
||||
@@ -94,9 +94,9 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canShowAlternateBouncerForFingerprint_noFingerprintsEnrolled() {
|
||||
fun canShowAlternateBouncerForFingerprint_ifFingerprintIsNotUsuallyAllowed() {
|
||||
givenCanShowAlternateBouncer()
|
||||
biometricSettingsRepository.setFingerprintEnrolled(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
|
||||
|
||||
assertFalse(underTest.canShowAlternateBouncerForFingerprint())
|
||||
}
|
||||
@@ -104,15 +104,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun canShowAlternateBouncerForFingerprint_strongBiometricNotAllowed() {
|
||||
givenCanShowAlternateBouncer()
|
||||
biometricSettingsRepository.setStrongBiometricAllowed(false)
|
||||
|
||||
assertFalse(underTest.canShowAlternateBouncerForFingerprint())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canShowAlternateBouncerForFingerprint_devicePolicyDoesNotAllowFingerprint() {
|
||||
givenCanShowAlternateBouncer()
|
||||
biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
|
||||
|
||||
assertFalse(underTest.canShowAlternateBouncerForFingerprint())
|
||||
}
|
||||
@@ -189,14 +181,13 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
|
||||
|
||||
private fun givenCanShowAlternateBouncer() {
|
||||
bouncerRepository.setAlternateBouncerUIAvailable(true)
|
||||
biometricSettingsRepository.setFingerprintEnrolled(true)
|
||||
biometricSettingsRepository.setStrongBiometricAllowed(true)
|
||||
biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
|
||||
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
|
||||
whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
|
||||
whenever(keyguardStateController.isUnlocked).thenReturn(false)
|
||||
}
|
||||
|
||||
private fun givenCannotShowAlternateBouncer() {
|
||||
biometricSettingsRepository.setFingerprintEnrolled(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.keyguard.KeyguardSecurityModel
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.R.string.keyguard_enter_pin
|
||||
import com.android.systemui.R.string.kg_too_many_failed_attempts_countdown
|
||||
import com.android.systemui.R.string.kg_unlock_with_pin_or_fp
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
|
||||
import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
|
||||
@@ -34,11 +33,11 @@ import com.android.systemui.coroutines.FlowValue
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
|
||||
import com.android.systemui.user.data.repository.FakeUserRepository
|
||||
import com.android.systemui.util.mockito.KotlinArgumentCaptor
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
@@ -49,14 +48,13 @@ import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var securityModel: KeyguardSecurityModel
|
||||
@Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
|
||||
@Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
|
||||
@Mock private lateinit var countDownTimerUtil: CountDownTimerUtil
|
||||
private lateinit var countDownTimerCallback: KotlinArgumentCaptor<CountDownTimerCallback>
|
||||
private lateinit var underTest: BouncerMessageInteractor
|
||||
@@ -73,10 +71,11 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
userRepository.setUserInfos(listOf(PRIMARY_USER))
|
||||
testScope = TestScope()
|
||||
countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
|
||||
biometricSettingsRepository = FakeBiometricSettingsRepository()
|
||||
|
||||
allowTestableLooperAsMainThread()
|
||||
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
|
||||
whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
|
||||
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
|
||||
}
|
||||
|
||||
suspend fun TestScope.init() {
|
||||
@@ -86,7 +85,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
underTest =
|
||||
BouncerMessageInteractor(
|
||||
repository = repository,
|
||||
factory = BouncerMessageFactory(updateMonitor, securityModel),
|
||||
factory = BouncerMessageFactory(biometricSettingsRepository, securityModel),
|
||||
userRepository = userRepository,
|
||||
countDownTimerUtil = countDownTimerUtil,
|
||||
featureFlags = featureFlags
|
||||
@@ -151,7 +150,8 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
underTest.setCustomMessage("not empty")
|
||||
|
||||
val customMessage = repository.customMessage
|
||||
assertThat(customMessage.value!!.message!!.messageResId).isEqualTo(keyguard_enter_pin)
|
||||
assertThat(customMessage.value!!.message!!.messageResId)
|
||||
.isEqualTo(kg_unlock_with_pin_or_fp)
|
||||
assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty")
|
||||
|
||||
underTest.setCustomMessage(null)
|
||||
@@ -168,7 +168,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
val faceAcquisitionMessage = repository.faceAcquisitionMessage
|
||||
|
||||
assertThat(faceAcquisitionMessage.value!!.message!!.messageResId)
|
||||
.isEqualTo(keyguard_enter_pin)
|
||||
.isEqualTo(kg_unlock_with_pin_or_fp)
|
||||
assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message)
|
||||
.isEqualTo("not empty")
|
||||
|
||||
@@ -186,7 +186,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage
|
||||
|
||||
assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId)
|
||||
.isEqualTo(keyguard_enter_pin)
|
||||
.isEqualTo(kg_unlock_with_pin_or_fp)
|
||||
assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message)
|
||||
.isEqualTo("not empty")
|
||||
|
||||
@@ -275,7 +275,8 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
|
||||
repository.setBiometricLockedOutMessage(null)
|
||||
|
||||
// sets the default message if everything else is null
|
||||
assertThat(bouncerMessage()!!.message!!.messageResId).isEqualTo(keyguard_enter_pin)
|
||||
assertThat(bouncerMessage()!!.message!!.messageResId)
|
||||
.isEqualTo(kg_unlock_with_pin_or_fp)
|
||||
}
|
||||
|
||||
private fun message(value: String): BouncerMessageModel {
|
||||
|
||||
@@ -36,6 +36,11 @@ import com.android.systemui.R
|
||||
import com.android.systemui.RoboPilotTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.biometrics.AuthController
|
||||
import com.android.systemui.biometrics.data.repository.FaceSensorInfo
|
||||
import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
|
||||
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.keyguard.data.repository.BiometricType.FACE
|
||||
@@ -63,6 +68,7 @@ import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.isNull
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.atLeastOnce
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
@@ -89,6 +95,8 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
ArgumentCaptor<IBiometricEnabledOnKeyguardCallback.Stub>
|
||||
private lateinit var userRepository: FakeUserRepository
|
||||
private lateinit var devicePostureRepository: FakeDevicePostureRepository
|
||||
private lateinit var facePropertyRepository: FakeFacePropertyRepository
|
||||
private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
|
||||
|
||||
private lateinit var testDispatcher: TestDispatcher
|
||||
private lateinit var testScope: TestScope
|
||||
@@ -102,6 +110,8 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
testScope = TestScope(testDispatcher)
|
||||
userRepository = FakeUserRepository()
|
||||
devicePostureRepository = FakeDevicePostureRepository()
|
||||
facePropertyRepository = FakeFacePropertyRepository()
|
||||
fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
|
||||
}
|
||||
|
||||
private suspend fun createBiometricSettingsRepository() {
|
||||
@@ -120,74 +130,110 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
biometricManager = biometricManager,
|
||||
devicePostureRepository = devicePostureRepository,
|
||||
dumpManager = dumpManager,
|
||||
facePropertyRepository = facePropertyRepository,
|
||||
fingerprintPropertyRepository = fingerprintPropertyRepository,
|
||||
)
|
||||
testScope.runCurrent()
|
||||
fingerprintPropertyRepository.setProperties(
|
||||
1,
|
||||
SensorStrength.STRONG,
|
||||
FingerprintSensorType.UDFPS_OPTICAL,
|
||||
emptyMap()
|
||||
)
|
||||
verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture())
|
||||
verify(authController, atLeastOnce()).addCallback(authControllerCallback.capture())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fingerprintEnrollmentChange() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
val fingerprintEnrolled = collectLastValue(underTest.isFingerprintEnrolled)
|
||||
val fingerprintAllowed = collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
|
||||
runCurrent()
|
||||
|
||||
verify(authController).addCallback(authControllerCallback.capture())
|
||||
whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true)
|
||||
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
|
||||
assertThat(fingerprintEnrolled()).isTrue()
|
||||
assertThat(fingerprintAllowed()).isTrue()
|
||||
|
||||
whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(false)
|
||||
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, ANOTHER_USER_ID, false)
|
||||
assertThat(fingerprintEnrolled()).isTrue()
|
||||
assertThat(fingerprintAllowed()).isTrue()
|
||||
|
||||
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, false)
|
||||
assertThat(fingerprintEnrolled()).isFalse()
|
||||
assertThat(fingerprintAllowed()).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun strongBiometricAllowedChange() =
|
||||
testScope.runTest {
|
||||
fingerprintIsEnrolled()
|
||||
doNotDisableKeyguardAuthFeatures()
|
||||
createBiometricSettingsRepository()
|
||||
val strongBiometricAllowed = collectLastValue(underTest.isStrongBiometricAllowed)
|
||||
|
||||
val strongBiometricAllowed by
|
||||
collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
|
||||
runCurrent()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
assertThat(strongBiometricAllowed()).isTrue()
|
||||
assertThat(strongBiometricAllowed).isTrue()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_BOOT, PRIMARY_USER_ID)
|
||||
assertThat(strongBiometricAllowed()).isFalse()
|
||||
assertThat(strongBiometricAllowed).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun convenienceBiometricAllowedChange() =
|
||||
testScope.runTest {
|
||||
overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false)
|
||||
deviceIsInPostureThatSupportsFaceAuth()
|
||||
faceAuthIsEnrolled()
|
||||
faceAuthIsNonStrongBiometric()
|
||||
createBiometricSettingsRepository()
|
||||
val convenienceBiometricAllowed =
|
||||
collectLastValue(underTest.isNonStrongBiometricAllowed)
|
||||
runCurrent()
|
||||
val convenienceFaceAuthAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
|
||||
doNotDisableKeyguardAuthFeatures()
|
||||
faceAuthIsEnabledByBiometricManager()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
assertThat(convenienceBiometricAllowed()).isTrue()
|
||||
runCurrent()
|
||||
assertThat(convenienceFaceAuthAllowed).isTrue()
|
||||
|
||||
onNonStrongAuthChanged(false, ANOTHER_USER_ID)
|
||||
assertThat(convenienceBiometricAllowed()).isTrue()
|
||||
assertThat(convenienceFaceAuthAllowed).isTrue()
|
||||
|
||||
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
|
||||
assertThat(convenienceBiometricAllowed()).isFalse()
|
||||
assertThat(convenienceFaceAuthAllowed).isFalse()
|
||||
mContext.orCreateTestableResources.removeOverride(
|
||||
com.android.internal.R.bool.config_strongAuthRequiredOnBoot
|
||||
)
|
||||
}
|
||||
|
||||
private fun faceAuthIsNonStrongBiometric() {
|
||||
facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.CONVENIENCE))
|
||||
}
|
||||
|
||||
private fun faceAuthIsStrongBiometric() {
|
||||
facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
|
||||
}
|
||||
|
||||
private fun deviceIsInPostureThatSupportsFaceAuth() {
|
||||
overrideResource(
|
||||
R.integer.config_face_auth_supported_posture,
|
||||
DevicePostureController.DEVICE_POSTURE_FLIPPED
|
||||
)
|
||||
devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenStrongAuthRequiredAfterBoot_nonStrongBiometricNotAllowed() =
|
||||
testScope.runTest {
|
||||
overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, true)
|
||||
createBiometricSettingsRepository()
|
||||
faceAuthIsNonStrongBiometric()
|
||||
faceAuthIsEnrolled()
|
||||
doNotDisableKeyguardAuthFeatures()
|
||||
|
||||
val convenienceBiometricAllowed =
|
||||
collectLastValue(underTest.isNonStrongBiometricAllowed)
|
||||
val convenienceBiometricAllowed = collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
|
||||
runCurrent()
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
|
||||
@@ -201,16 +247,24 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
fun whenStrongBiometricAuthIsNotAllowed_nonStrongBiometrics_alsoNotAllowed() =
|
||||
testScope.runTest {
|
||||
overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false)
|
||||
faceAuthIsNonStrongBiometric()
|
||||
deviceIsInPostureThatSupportsFaceAuth()
|
||||
faceAuthIsEnrolled()
|
||||
createBiometricSettingsRepository()
|
||||
|
||||
val convenienceBiometricAllowed =
|
||||
collectLastValue(underTest.isNonStrongBiometricAllowed)
|
||||
doNotDisableKeyguardAuthFeatures()
|
||||
faceAuthIsEnabledByBiometricManager()
|
||||
runCurrent()
|
||||
|
||||
val convenienceBiometricAllowed by
|
||||
collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
assertThat(convenienceBiometricAllowed()).isTrue()
|
||||
runCurrent()
|
||||
assertThat(convenienceBiometricAllowed).isTrue()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, PRIMARY_USER_ID)
|
||||
assertThat(convenienceBiometricAllowed()).isFalse()
|
||||
assertThat(convenienceBiometricAllowed).isFalse()
|
||||
mContext.orCreateTestableResources.removeOverride(
|
||||
com.android.internal.R.bool.config_strongAuthRequiredOnBoot
|
||||
)
|
||||
@@ -229,9 +283,11 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun fingerprintDisabledByDpmChange() =
|
||||
testScope.runTest {
|
||||
fingerprintIsEnrolled(PRIMARY_USER_ID)
|
||||
createBiometricSettingsRepository()
|
||||
|
||||
val fingerprintEnabledByDevicePolicy =
|
||||
collectLastValue(underTest.isFingerprintEnabledByDevicePolicy)
|
||||
collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
|
||||
runCurrent()
|
||||
|
||||
whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
|
||||
@@ -244,43 +300,57 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
assertThat(fingerprintEnabledByDevicePolicy()).isTrue()
|
||||
}
|
||||
|
||||
private fun fingerprintIsEnrolled(userId: Int = PRIMARY_USER_ID) {
|
||||
whenever(authController.isFingerprintEnrolled(userId)).thenReturn(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceEnrollmentChangeIsPropagatedForTheCurrentUser() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
faceAuthIsEnabledByBiometricManager()
|
||||
|
||||
doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
|
||||
|
||||
runCurrent()
|
||||
clearInvocations(authController)
|
||||
|
||||
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false)
|
||||
val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
|
||||
val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
|
||||
|
||||
assertThat(faceEnrolled()).isFalse()
|
||||
assertThat(faceAuthAllowed()).isFalse()
|
||||
verify(authController).addCallback(authControllerCallback.capture())
|
||||
enrollmentChange(REAR_FINGERPRINT, PRIMARY_USER_ID, true)
|
||||
|
||||
assertThat(faceEnrolled()).isFalse()
|
||||
assertThat(faceAuthAllowed()).isFalse()
|
||||
|
||||
enrollmentChange(SIDE_FINGERPRINT, PRIMARY_USER_ID, true)
|
||||
|
||||
assertThat(faceEnrolled()).isFalse()
|
||||
assertThat(faceAuthAllowed()).isFalse()
|
||||
|
||||
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
|
||||
|
||||
assertThat(faceEnrolled()).isFalse()
|
||||
assertThat(faceAuthAllowed()).isFalse()
|
||||
|
||||
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
|
||||
|
||||
enrollmentChange(FACE, ANOTHER_USER_ID, true)
|
||||
|
||||
assertThat(faceEnrolled()).isFalse()
|
||||
assertThat(faceAuthAllowed()).isFalse()
|
||||
|
||||
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(true)
|
||||
faceAuthIsEnrolled()
|
||||
|
||||
enrollmentChange(FACE, PRIMARY_USER_ID, true)
|
||||
|
||||
assertThat(faceEnrolled()).isTrue()
|
||||
assertThat(faceAuthAllowed()).isTrue()
|
||||
}
|
||||
|
||||
private fun faceAuthIsEnabledByBiometricManager(userId: Int = PRIMARY_USER_ID) {
|
||||
verify(biometricManager, atLeastOnce())
|
||||
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
|
||||
biometricManagerCallback.value.onChanged(true, userId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceEnrollmentStatusOfNewUserUponUserSwitch() =
|
||||
testScope.runTest {
|
||||
@@ -290,21 +360,26 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
|
||||
whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(false)
|
||||
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
|
||||
val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
|
||||
val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
|
||||
|
||||
assertThat(faceEnrolled()).isFalse()
|
||||
assertThat(faceAuthAllowed()).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceEnrollmentChangesArePropagatedAfterUserSwitch() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
verify(biometricManager)
|
||||
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
|
||||
|
||||
userRepository.setSelectedUserInfo(ANOTHER_USER)
|
||||
doNotDisableKeyguardAuthFeatures(ANOTHER_USER_ID)
|
||||
biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID)
|
||||
|
||||
runCurrent()
|
||||
clearInvocations(authController)
|
||||
|
||||
val faceEnrolled = collectLastValue(underTest.isFaceEnrolled)
|
||||
val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
|
||||
runCurrent()
|
||||
|
||||
verify(authController).addCallback(authControllerCallback.capture())
|
||||
@@ -312,12 +387,14 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
|
||||
enrollmentChange(FACE, ANOTHER_USER_ID, true)
|
||||
|
||||
assertThat(faceEnrolled()).isTrue()
|
||||
assertThat(faceAuthAllowed()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun devicePolicyControlsFaceAuthenticationEnabledState() =
|
||||
testScope.runTest {
|
||||
faceAuthIsEnrolled()
|
||||
|
||||
createBiometricSettingsRepository()
|
||||
verify(biometricManager)
|
||||
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
|
||||
@@ -325,62 +402,70 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
|
||||
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT or KEYGUARD_DISABLE_FACE)
|
||||
|
||||
val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
|
||||
val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
|
||||
runCurrent()
|
||||
|
||||
broadcastDPMStateChange()
|
||||
|
||||
assertThat(isFaceAuthEnabled()).isFalse()
|
||||
assertThat(isFaceAuthAllowed()).isFalse()
|
||||
|
||||
biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID)
|
||||
runCurrent()
|
||||
assertThat(isFaceAuthEnabled()).isFalse()
|
||||
assertThat(isFaceAuthAllowed()).isFalse()
|
||||
|
||||
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
|
||||
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT)
|
||||
broadcastDPMStateChange()
|
||||
|
||||
assertThat(isFaceAuthEnabled()).isTrue()
|
||||
assertThat(isFaceAuthAllowed()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun biometricManagerControlsFaceAuthenticationEnabledStatus() =
|
||||
testScope.runTest {
|
||||
faceAuthIsEnrolled()
|
||||
|
||||
createBiometricSettingsRepository()
|
||||
verify(biometricManager)
|
||||
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
|
||||
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(PRIMARY_USER_ID)))
|
||||
.thenReturn(0)
|
||||
broadcastDPMStateChange()
|
||||
val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
|
||||
val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
|
||||
|
||||
assertThat(isFaceAuthEnabled()).isFalse()
|
||||
assertThat(isFaceAuthAllowed()).isFalse()
|
||||
|
||||
// Value changes for another user
|
||||
biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthEnabled()).isFalse()
|
||||
assertThat(isFaceAuthAllowed()).isFalse()
|
||||
|
||||
// Value changes for current user.
|
||||
biometricManagerCallback.value.onChanged(true, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthEnabled()).isTrue()
|
||||
assertThat(isFaceAuthAllowed()).isTrue()
|
||||
}
|
||||
|
||||
private fun faceAuthIsEnrolled(userId: Int = PRIMARY_USER_ID) {
|
||||
whenever(authController.isFaceAuthEnrolled(userId)).thenReturn(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun userChange_biometricEnabledChange_handlesRaceCondition() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
|
||||
|
||||
verify(biometricManager)
|
||||
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
|
||||
val isFaceAuthEnabled = collectLastValue(underTest.isFaceAuthenticationEnabled)
|
||||
val isFaceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
|
||||
biometricManagerCallback.value.onChanged(true, ANOTHER_USER_ID)
|
||||
runCurrent()
|
||||
|
||||
userRepository.setSelectedUserInfo(ANOTHER_USER)
|
||||
runCurrent()
|
||||
|
||||
assertThat(isFaceAuthEnabled()).isTrue()
|
||||
assertThat(isFaceAuthAllowed()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -388,9 +473,9 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
|
||||
collectLastValue(underTest.isFaceAuthenticationEnabled)()
|
||||
collectLastValue(underTest.isFaceAuthenticationEnabled)()
|
||||
collectLastValue(underTest.isFaceAuthenticationEnabled)()
|
||||
collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)()
|
||||
collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)()
|
||||
collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)()
|
||||
|
||||
verify(biometricManager, times(1)).registerEnabledOnKeyguardCallback(any())
|
||||
}
|
||||
@@ -495,10 +580,138 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
|
||||
assertThat(authFlags()!!.flag).isEqualTo(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFaceIsClass3() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
val isFaceAuthCurrentlyAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
|
||||
|
||||
faceAuthIsEnrolled()
|
||||
deviceIsInPostureThatSupportsFaceAuth()
|
||||
doNotDisableKeyguardAuthFeatures()
|
||||
faceAuthIsStrongBiometric()
|
||||
faceAuthIsEnabledByBiometricManager()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthCurrentlyAllowed).isTrue()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthCurrentlyAllowed).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun faceAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFaceIsNotStrong() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
val isFaceAuthCurrentlyAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
|
||||
|
||||
faceAuthIsEnrolled()
|
||||
deviceIsInPostureThatSupportsFaceAuth()
|
||||
doNotDisableKeyguardAuthFeatures()
|
||||
faceAuthIsNonStrongBiometric()
|
||||
faceAuthIsEnabledByBiometricManager()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthCurrentlyAllowed).isFalse()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthCurrentlyAllowed).isFalse()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFaceAuthCurrentlyAllowed).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fpAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFpIsNotStrong() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
val isFingerprintCurrentlyAllowed by
|
||||
collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
|
||||
|
||||
fingerprintIsEnrolled(PRIMARY_USER_ID)
|
||||
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
|
||||
doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
|
||||
runCurrent()
|
||||
|
||||
fingerprintPropertyRepository.setProperties(
|
||||
1,
|
||||
SensorStrength.STRONG,
|
||||
FingerprintSensorType.UDFPS_OPTICAL,
|
||||
emptyMap()
|
||||
)
|
||||
// Non strong auth is not allowed now, FP is marked strong
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFingerprintCurrentlyAllowed).isTrue()
|
||||
|
||||
fingerprintPropertyRepository.setProperties(
|
||||
1,
|
||||
SensorStrength.CONVENIENCE,
|
||||
FingerprintSensorType.UDFPS_OPTICAL,
|
||||
emptyMap()
|
||||
)
|
||||
assertThat(isFingerprintCurrentlyAllowed).isFalse()
|
||||
|
||||
fingerprintPropertyRepository.setProperties(
|
||||
1,
|
||||
SensorStrength.WEAK,
|
||||
FingerprintSensorType.UDFPS_OPTICAL,
|
||||
emptyMap()
|
||||
)
|
||||
assertThat(isFingerprintCurrentlyAllowed).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fpAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFpIsStrong() =
|
||||
testScope.runTest {
|
||||
createBiometricSettingsRepository()
|
||||
val isFingerprintCurrentlyAllowed by
|
||||
collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
|
||||
|
||||
fingerprintIsEnrolled(PRIMARY_USER_ID)
|
||||
enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
|
||||
doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
|
||||
runCurrent()
|
||||
|
||||
fingerprintPropertyRepository.setProperties(
|
||||
1,
|
||||
SensorStrength.STRONG,
|
||||
FingerprintSensorType.UDFPS_OPTICAL,
|
||||
emptyMap()
|
||||
)
|
||||
// Non strong auth is not allowed now, FP is marked strong
|
||||
onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFingerprintCurrentlyAllowed).isFalse()
|
||||
|
||||
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
|
||||
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
|
||||
|
||||
assertThat(isFingerprintCurrentlyAllowed).isTrue()
|
||||
}
|
||||
|
||||
private fun enrollmentChange(biometricType: BiometricType, userId: Int, enabled: Boolean) {
|
||||
authControllerCallback.value.onEnrollmentsChanged(biometricType, userId, enabled)
|
||||
}
|
||||
|
||||
private fun doNotDisableKeyguardAuthFeatures(userId: Int = PRIMARY_USER_ID) {
|
||||
whenever(devicePolicyManager.getKeyguardDisabledFeatures(isNull(), eq(userId)))
|
||||
.thenReturn(0)
|
||||
broadcastDPMStateChange()
|
||||
}
|
||||
|
||||
private fun broadcastDPMStateChange() {
|
||||
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
|
||||
context,
|
||||
|
||||
@@ -40,9 +40,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.RoboPilotTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.biometrics.data.repository.FaceSensorInfo
|
||||
import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
|
||||
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
||||
import com.android.systemui.coroutines.FlowValue
|
||||
@@ -255,7 +253,6 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
faceAuthBuffer,
|
||||
keyguardTransitionInteractor,
|
||||
featureFlags,
|
||||
fakeFacePropertyRepository,
|
||||
dumpManager,
|
||||
)
|
||||
}
|
||||
@@ -525,15 +522,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunIfFaceIsNotEnrolled() =
|
||||
fun authenticateDoesNotRunIfFaceIsNotUsuallyAllowed() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForFaceAuth { biometricSettingsRepository.setFaceEnrolled(false) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunIfFaceIsNotEnabled() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForFaceAuth { biometricSettingsRepository.setIsFaceAuthEnabled(false) }
|
||||
testGatingCheckForFaceAuth {
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -589,21 +582,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunWhenNonStrongBiometricIsNotAllowed() =
|
||||
fun authenticateDoesNotRunWhenFaceAuthIsNotCurrentlyAllowedToRun() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForFaceAuth {
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticateDoesNotRunWhenStrongBiometricIsNotAllowedAndFaceSensorIsStrong() =
|
||||
testScope.runTest {
|
||||
fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
|
||||
runCurrent()
|
||||
|
||||
testGatingCheckForFaceAuth(isFaceStrong = true) {
|
||||
biometricSettingsRepository.setIsStrongBiometricAllowed(false)
|
||||
biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -662,7 +644,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
|
||||
// Flip one precondition to false.
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
|
||||
biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false)
|
||||
assertThat(canFaceAuthRun()).isFalse()
|
||||
underTest.authenticate(
|
||||
FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER,
|
||||
@@ -827,15 +809,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectDoesNotRunWhenFaceIsNotEnrolled() =
|
||||
fun detectDoesNotRunWhenFaceIsNotUsuallyAllowed() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForDetect { biometricSettingsRepository.setFaceEnrolled(false) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectDoesNotRunWhenFaceIsNotEnabled() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForDetect { biometricSettingsRepository.setIsFaceAuthEnabled(false) }
|
||||
testGatingCheckForDetect {
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -932,23 +910,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectDoesNotRunWhenNonStrongBiometricIsAllowed() =
|
||||
fun detectDoesNotRunWhenFaceAuthIsCurrentlyAllowedToRun() =
|
||||
testScope.runTest {
|
||||
testGatingCheckForDetect {
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectDoesNotRunWhenStrongBiometricIsAllowedAndFaceAuthSensorStrengthIsStrong() =
|
||||
testScope.runTest {
|
||||
fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
|
||||
runCurrent()
|
||||
|
||||
testGatingCheckForDetect(isFaceStrong = true) {
|
||||
biometricSettingsRepository.setIsStrongBiometricAllowed(true)
|
||||
// this shouldn't matter as face is set as a strong sensor
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
|
||||
biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1043,12 +1008,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
faceAuthenticateIsCalled()
|
||||
}
|
||||
|
||||
private suspend fun TestScope.testGatingCheckForFaceAuth(
|
||||
isFaceStrong: Boolean = false,
|
||||
gatingCheckModifier: () -> Unit
|
||||
) {
|
||||
private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) {
|
||||
initCollectors()
|
||||
allPreconditionsToRunFaceAuthAreTrue(isFaceStrong)
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
|
||||
gatingCheckModifier()
|
||||
runCurrent()
|
||||
@@ -1057,7 +1019,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
assertThat(underTest.canRunFaceAuth.value).isFalse()
|
||||
|
||||
// flip the gating check back on.
|
||||
allPreconditionsToRunFaceAuthAreTrue(isFaceStrong)
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
|
||||
triggerFaceAuth(false)
|
||||
|
||||
@@ -1076,19 +1038,12 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
faceAuthenticateIsNotCalled()
|
||||
}
|
||||
|
||||
private suspend fun TestScope.testGatingCheckForDetect(
|
||||
isFaceStrong: Boolean = false,
|
||||
gatingCheckModifier: () -> Unit
|
||||
) {
|
||||
private suspend fun TestScope.testGatingCheckForDetect(gatingCheckModifier: () -> Unit) {
|
||||
initCollectors()
|
||||
allPreconditionsToRunFaceAuthAreTrue()
|
||||
|
||||
if (isFaceStrong) {
|
||||
biometricSettingsRepository.setStrongBiometricAllowed(false)
|
||||
} else {
|
||||
// This will stop face auth from running but is required to be false for detect.
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(false)
|
||||
}
|
||||
// This will stop face auth from running but is required to be false for detect.
|
||||
biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(false)
|
||||
runCurrent()
|
||||
|
||||
assertThat(canFaceAuthRun()).isFalse()
|
||||
@@ -1123,13 +1078,9 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
cancellationSignal.value.setOnCancelListener { wasAuthCancelled = true }
|
||||
}
|
||||
|
||||
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue(
|
||||
isFaceStrong: Boolean = false
|
||||
) {
|
||||
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() {
|
||||
verify(faceManager, atLeastOnce())
|
||||
.addLockoutResetCallback(faceLockoutResetCallback.capture())
|
||||
biometricSettingsRepository.setFaceEnrolled(true)
|
||||
biometricSettingsRepository.setIsFaceAuthEnabled(true)
|
||||
underTest.resumeFaceAuth()
|
||||
trustRepository.setCurrentUserTrusted(false)
|
||||
keyguardRepository.setKeyguardGoingAway(false)
|
||||
@@ -1140,14 +1091,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
WakeSleepReason.OTHER
|
||||
)
|
||||
)
|
||||
if (isFaceStrong) {
|
||||
biometricSettingsRepository.setStrongBiometricAllowed(true)
|
||||
} else {
|
||||
biometricSettingsRepository.setIsNonStrongBiometricAllowed(true)
|
||||
}
|
||||
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
|
||||
biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
|
||||
biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
|
||||
biometricSettingsRepository.setIsUserInLockdown(false)
|
||||
fakeUserRepository.setSelectedUserInfo(primaryUser)
|
||||
biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
|
||||
faceLockoutResetCallback.value.onLockoutReset(0)
|
||||
bouncerRepository.setAlternateVisible(true)
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
|
||||
@@ -22,32 +22,24 @@ import com.android.systemui.keyguard.shared.model.AuthenticationFlags
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class FakeBiometricSettingsRepository : BiometricSettingsRepository {
|
||||
private val _isFingerprintEnrolledAndEnabled = MutableStateFlow(false)
|
||||
override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean>
|
||||
get() = _isFingerprintEnrolledAndEnabled
|
||||
|
||||
private val _isFingerprintEnrolled = MutableStateFlow<Boolean>(false)
|
||||
override val isFingerprintEnrolled: StateFlow<Boolean> = _isFingerprintEnrolled.asStateFlow()
|
||||
private val _isFingerprintAuthCurrentlyAllowed = MutableStateFlow(false)
|
||||
override val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean>
|
||||
get() = _isFingerprintAuthCurrentlyAllowed
|
||||
|
||||
private val _isFaceEnrolled = MutableStateFlow(false)
|
||||
override val isFaceEnrolled: Flow<Boolean>
|
||||
get() = _isFaceEnrolled
|
||||
private val _isFaceAuthEnrolledAndEnabled = MutableStateFlow(false)
|
||||
override val isFaceAuthEnrolledAndEnabled: Flow<Boolean>
|
||||
get() = _isFaceAuthEnrolledAndEnabled
|
||||
|
||||
private val _isFaceAuthEnabled = MutableStateFlow(false)
|
||||
override val isFaceAuthenticationEnabled: Flow<Boolean>
|
||||
get() = _isFaceAuthEnabled
|
||||
|
||||
private val _isStrongBiometricAllowed = MutableStateFlow(false)
|
||||
override val isStrongBiometricAllowed = _isStrongBiometricAllowed.asStateFlow()
|
||||
|
||||
private val _isNonStrongBiometricAllowed = MutableStateFlow(false)
|
||||
override val isNonStrongBiometricAllowed: StateFlow<Boolean>
|
||||
get() = _isNonStrongBiometricAllowed
|
||||
|
||||
private val _isFingerprintEnabledByDevicePolicy = MutableStateFlow(false)
|
||||
override val isFingerprintEnabledByDevicePolicy =
|
||||
_isFingerprintEnabledByDevicePolicy.asStateFlow()
|
||||
private val _isFaceAuthCurrentlyAllowed = MutableStateFlow(false)
|
||||
override val isFaceAuthCurrentlyAllowed: Flow<Boolean>
|
||||
get() = _isFaceAuthCurrentlyAllowed
|
||||
|
||||
private val _isFaceAuthSupportedInCurrentPosture = MutableStateFlow(false)
|
||||
override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean>
|
||||
@@ -59,34 +51,33 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
|
||||
private val _authFlags = MutableStateFlow(AuthenticationFlags(0, 0))
|
||||
override val authenticationFlags: Flow<AuthenticationFlags>
|
||||
get() = _authFlags
|
||||
fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) {
|
||||
_isFingerprintEnrolled.value = isFingerprintEnrolled
|
||||
}
|
||||
|
||||
fun setStrongBiometricAllowed(isStrongBiometricAllowed: Boolean) {
|
||||
_isStrongBiometricAllowed.value = isStrongBiometricAllowed
|
||||
}
|
||||
|
||||
fun setFingerprintEnabledByDevicePolicy(isFingerprintEnabledByDevicePolicy: Boolean) {
|
||||
_isFingerprintEnabledByDevicePolicy.value = isFingerprintEnabledByDevicePolicy
|
||||
}
|
||||
|
||||
fun setAuthenticationFlags(value: AuthenticationFlags) {
|
||||
_authFlags.value = value
|
||||
}
|
||||
|
||||
fun setFaceEnrolled(isFaceEnrolled: Boolean) {
|
||||
_isFaceEnrolled.value = isFaceEnrolled
|
||||
fun setIsFingerprintAuthEnrolledAndEnabled(value: Boolean) {
|
||||
_isFingerprintEnrolledAndEnabled.value = value
|
||||
_isFingerprintAuthCurrentlyAllowed.value = _isFingerprintAuthCurrentlyAllowed.value && value
|
||||
}
|
||||
|
||||
fun setIsFingerprintAuthCurrentlyAllowed(value: Boolean) {
|
||||
_isFingerprintAuthCurrentlyAllowed.value = value
|
||||
}
|
||||
|
||||
fun setIsFaceAuthEnrolledAndEnabled(value: Boolean) {
|
||||
_isFaceAuthEnrolledAndEnabled.value = value
|
||||
_isFaceAuthCurrentlyAllowed.value = _isFaceAuthCurrentlyAllowed.value && value
|
||||
}
|
||||
|
||||
fun setIsFaceAuthCurrentlyAllowed(value: Boolean) {
|
||||
_isFaceAuthCurrentlyAllowed.value = value
|
||||
}
|
||||
|
||||
fun setIsFaceAuthSupportedInCurrentPosture(value: Boolean) {
|
||||
_isFaceAuthSupportedInCurrentPosture.value = value
|
||||
}
|
||||
|
||||
fun setIsFaceAuthEnabled(enabled: Boolean) {
|
||||
_isFaceAuthEnabled.value = enabled
|
||||
}
|
||||
|
||||
fun setIsUserInLockdown(value: Boolean) {
|
||||
if (value) {
|
||||
setAuthenticationFlags(
|
||||
@@ -105,12 +96,4 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setIsNonStrongBiometricAllowed(value: Boolean) {
|
||||
_isNonStrongBiometricAllowed.value = value
|
||||
}
|
||||
|
||||
fun setIsStrongBiometricAllowed(value: Boolean) {
|
||||
_isStrongBiometricAllowed.value = value
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user