Loading packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt +50 −52 Original line number Diff line number Diff line Loading @@ -281,16 +281,23 @@ constructor( *gatingConditionsForAuthAndDetect(), Pair(isBypassEnabled, "isBypassEnabled"), Pair( biometricSettingsRepository.isFaceAuthCurrentlyAllowed .isFalse() .or(isLockedOut) .or(keyguardRepository.isKeyguardDismissible), combine( biometricSettingsRepository.isFaceAuthCurrentlyAllowed, isLockedOut, keyguardRepository.isKeyguardDismissible, ) { faceAuthCurrentlyAllowed, isLockedOut, isKeyguardDismissible -> !faceAuthCurrentlyAllowed || isLockedOut || isKeyguardDismissible }, "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted", ), // We don't want to run face detect if fingerprint can be used to unlock the // device bc it's not possible to authenticate with FP from the bouncer (UDFPS) Pair( and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(), combine(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning) { isUdfps, fingerprintAuthRunning -> !(isUdfps && fingerprintAuthRunning) }, "udfpsAuthIsNotPossibleAnymore", ), ) Loading Loading @@ -385,13 +392,14 @@ constructor( private fun gatingConditionsForAuthAndDetect(): Array<Pair<Flow<Boolean>, String>> { return arrayOf( Pair( and( combine( displayStateInteractor.isDefaultDisplayOff, keyguardTransitionInteractor.isFinishedInStateWhere( KeyguardState::deviceIsAwakeInState ), ) .isFalse(), ) { defaultDisplayOff, finishedInAwakeState -> !(defaultDisplayOff && finishedInAwakeState) }, // this can happen if an app is requesting for screen off, the display can // turn off without wakefulness.isStartingToSleepOrAsleep calls "displayIsNotOffWhileFullyTransitionedToAwake", Loading @@ -402,23 +410,21 @@ constructor( ), Pair( if (SceneContainerFlag.isEnabled) { sceneInteractor .get() .transitionState .map { it.isTransitioning(to = Scenes.Gone) || it.isIdle(Scenes.Gone) } .isFalse() sceneInteractor.get().transitionState.map { !it.isTransitioning(to = Scenes.Gone) && !it.isIdle(Scenes.Gone) } } else { (keyguardTransitionInteractor .isFinishedIn(KeyguardState.GONE) .or( combine( keyguardTransitionInteractor.isFinishedIn(KeyguardState.GONE), keyguardTransitionInteractor.isInTransition( Edge.create(to = Scenes.Gone), Edge.create(to = KeyguardState.GONE), ) )) .isFalse() ), ) { finishedInGone, transitioningToGone -> !finishedInGone && !transitioningToGone } }, "keyguardNotGoneOrTransitioningToGone", "keyguardNotGoneAndNotTransitioningToGone", ), Pair( keyguardTransitionInteractor Loading @@ -427,19 +433,19 @@ constructor( "deviceNotTransitioningToAsleepState", ), Pair( keyguardInteractor.isSecureCameraActive .isFalse() .or( alternateBouncerInteractor.isVisible.or( combine( keyguardInteractor.isSecureCameraActive, alternateBouncerInteractor.isVisible, if (SceneContainerFlag.isEnabled) { sceneInteractor.get().transitionState.map { it.isIdle(overlay = Overlays.Bouncer) } } else { keyguardInteractor.primaryBouncerShowing } ) ), }, ) { isSecureCameraActive, alternateBouncerVisible, primaryBouncerShowing -> !isSecureCameraActive || alternateBouncerVisible || primaryBouncerShowing }, "secureCameraNotActiveOrAnyBouncerIsShowing", ), Pair( Loading @@ -452,10 +458,10 @@ constructor( ), Pair(keyguardRepository.isKeyguardShowing, "isKeyguardShowing"), Pair( userRepository.selectedUser .map { it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS } .isFalse(), "userSwitchingInProgress", userRepository.selectedUser.map { it.selectionStatus != SelectionStatus.SELECTION_IN_PROGRESS }, "userSwitchingNotInProgress", ), ) } Loading Loading @@ -769,14 +775,6 @@ constructor( } } /** Combine two boolean flows by and-ing both of them */ private fun and(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) = flow.combine(anotherFlow) { a, b -> a && b } /** Combine two boolean flows by or-ing both of them */ private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) = this.combine(anotherFlow) { a, b -> a || b } /** "Not" the given flow. The return [Flow] will be true when [this] flow is false. */ private fun Flow<Boolean>.isFalse(): Flow<Boolean> { return this.map { !it } Loading packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt +46 −34 Original line number Diff line number Diff line Loading @@ -188,7 +188,7 @@ constructor( private val devicePolicyChangedForAllUsers = broadcastDispatcher.broadcastFlow( filter = IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), user = UserHandle.ALL user = UserHandle.ALL, ) private val isFingerprintEnrolled: Flow<Boolean> = Loading @@ -199,13 +199,13 @@ constructor( override fun onEnrollmentsChanged( sensorBiometricType: BiometricType, userId: Int, hasEnrollments: Boolean hasEnrollments: Boolean, ) { if (sensorBiometricType.isFingerprint && userId == currentUserId) { trySendWithFailureLogging( hasEnrollments, TAG, "update fpEnrollment" "update fpEnrollment", ) } } Loading @@ -214,7 +214,7 @@ constructor( trySendWithFailureLogging( authController.isFingerprintEnrolled(currentUserId), TAG, "Initial value of fingerprint enrollment" "Initial value of fingerprint enrollment", ) awaitClose { authController.removeCallback(callback) } } Loading @@ -228,13 +228,13 @@ constructor( override fun onEnrollmentsChanged( sensorBiometricType: BiometricType, userId: Int, hasEnrollments: Boolean hasEnrollments: Boolean, ) { if (sensorBiometricType == BiometricType.FACE) { trySendWithFailureLogging( authController.isFaceAuthEnrolled(selectedUserId), TAG, "Face enrollment changed" "Face enrollment changed", ) } } Loading @@ -243,7 +243,7 @@ constructor( trySendWithFailureLogging( authController.isFaceAuthEnrolled(selectedUserId), TAG, "Initial value of face auth enrollment" "Initial value of face auth enrollment", ) awaitClose { authController.removeCallback(callback) } } Loading Loading @@ -327,8 +327,8 @@ constructor( SharingStarted.Eagerly, strongAuthTracker.isBiometricAllowedForUser( true, userRepository.getSelectedUserInfo().id ) userRepository.getSelectedUserInfo().id, ), ) private val isNonStrongBiometricAllowed: StateFlow<Boolean> = Loading @@ -337,8 +337,8 @@ constructor( SharingStarted.Eagerly, strongAuthTracker.isBiometricAllowedForUser( false, userRepository.getSelectedUserInfo().id ) userRepository.getSelectedUserInfo().id, ), ) private val isFingerprintBiometricAllowed: Flow<Boolean> = Loading @@ -363,33 +363,47 @@ constructor( } override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean> = isFingerprintEnrolled .and(isFingerprintEnabledForCurrentUser) .and(isFingerprintEnabledByDevicePolicy) combine( isFingerprintEnrolled, isFingerprintEnabledForCurrentUser, isFingerprintEnabledByDevicePolicy, ) { enrolled, enabledForCurrentUser, devicePolicyEnabled -> enrolled && enabledForCurrentUser && devicePolicyEnabled } .stateIn(scope, SharingStarted.Eagerly, false) override val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean> = isFingerprintEnrolledAndEnabled .and(isFingerprintBiometricAllowed) combine(isFingerprintEnrolledAndEnabled, isFingerprintBiometricAllowed) { enrolledAndEnabled, allowed -> enrolledAndEnabled && allowed } .stateIn(scope, SharingStarted.Eagerly, false) override val isFaceAuthEnrolledAndEnabled: StateFlow<Boolean> = isFaceAuthenticationEnabled .and(isFaceEnrolled) .and(mobileConnectionsRepository.isAnySimSecure.isFalse()) combine( isFaceAuthenticationEnabled, isFaceEnrolled, mobileConnectionsRepository.isAnySimSecure, ) { enabled, enrolled, isAnySimSecure -> enabled && enrolled && !isAnySimSecure } .stateIn(scope, SharingStarted.Eagerly, false) override val isFaceAuthCurrentlyAllowed: Flow<Boolean> = isFaceAuthEnrolledAndEnabled .and(isFaceBiometricsAllowed) .and(isFaceAuthSupportedInCurrentPosture) combine( isFaceAuthEnrolledAndEnabled, isFaceBiometricsAllowed, isFaceAuthSupportedInCurrentPosture, ) { enrolledAndEnabled, allowed, supportedInCurrentPosture -> enrolledAndEnabled && allowed && supportedInCurrentPosture } } private class StrongAuthTracker( private val userRepository: UserRepository, @ShadeDisplayAware context: Context? ) : LockPatternUtils.StrongAuthTracker(context) { @ShadeDisplayAware context: Context?, ) : LockPatternUtils.StrongAuthTracker(context) { private val selectedUserId = userRepository.selectedUserInfo.map { it.id }.distinctUntilChanged() Loading Loading @@ -418,8 +432,8 @@ private class StrongAuthTracker( /** isNonStrongBiometricAllowed for the current user. */ val isNonStrongBiometricAllowed: Flow<Boolean> = selectedUserId .flatMapLatest { userId -> combine( selectedUserId.flatMapLatest { userId -> _nonStrongBiometricAllowed .filter { it.first == userId } .map { it.second } Loading @@ -427,8 +441,11 @@ private class StrongAuthTracker( Log.d(TAG, "isNonStrongBiometricAllowed changed for current user: $it") } .onStart { emit(isNonStrongBiometricAllowedAfterIdleTimeout(userId)) } }, isStrongBiometricAllowed, ) { nonStrongBiometricAllowed, strongBiometricAllowed -> nonStrongBiometricAllowed && strongBiometricAllowed } .and(isStrongBiometricAllowed) private val currentUserId get() = userRepository.getSelectedUserInfo().id Loading @@ -454,8 +471,3 @@ private fun DevicePolicyManager.isFingerprintDisabled(userId: Int): Boolean = private fun DevicePolicyManager.isNotActive(userId: Int, policy: Int): Boolean = (getKeyguardDisabledFeatures(null, userId) and policy) == 0 private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>): Flow<Boolean> = this.combine(anotherFlow) { a, b -> a && b } private fun Flow<Boolean>.isFalse(): Flow<Boolean> = this.map { !it } Loading
packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt +50 −52 Original line number Diff line number Diff line Loading @@ -281,16 +281,23 @@ constructor( *gatingConditionsForAuthAndDetect(), Pair(isBypassEnabled, "isBypassEnabled"), Pair( biometricSettingsRepository.isFaceAuthCurrentlyAllowed .isFalse() .or(isLockedOut) .or(keyguardRepository.isKeyguardDismissible), combine( biometricSettingsRepository.isFaceAuthCurrentlyAllowed, isLockedOut, keyguardRepository.isKeyguardDismissible, ) { faceAuthCurrentlyAllowed, isLockedOut, isKeyguardDismissible -> !faceAuthCurrentlyAllowed || isLockedOut || isKeyguardDismissible }, "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted", ), // We don't want to run face detect if fingerprint can be used to unlock the // device bc it's not possible to authenticate with FP from the bouncer (UDFPS) Pair( and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(), combine(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning) { isUdfps, fingerprintAuthRunning -> !(isUdfps && fingerprintAuthRunning) }, "udfpsAuthIsNotPossibleAnymore", ), ) Loading Loading @@ -385,13 +392,14 @@ constructor( private fun gatingConditionsForAuthAndDetect(): Array<Pair<Flow<Boolean>, String>> { return arrayOf( Pair( and( combine( displayStateInteractor.isDefaultDisplayOff, keyguardTransitionInteractor.isFinishedInStateWhere( KeyguardState::deviceIsAwakeInState ), ) .isFalse(), ) { defaultDisplayOff, finishedInAwakeState -> !(defaultDisplayOff && finishedInAwakeState) }, // this can happen if an app is requesting for screen off, the display can // turn off without wakefulness.isStartingToSleepOrAsleep calls "displayIsNotOffWhileFullyTransitionedToAwake", Loading @@ -402,23 +410,21 @@ constructor( ), Pair( if (SceneContainerFlag.isEnabled) { sceneInteractor .get() .transitionState .map { it.isTransitioning(to = Scenes.Gone) || it.isIdle(Scenes.Gone) } .isFalse() sceneInteractor.get().transitionState.map { !it.isTransitioning(to = Scenes.Gone) && !it.isIdle(Scenes.Gone) } } else { (keyguardTransitionInteractor .isFinishedIn(KeyguardState.GONE) .or( combine( keyguardTransitionInteractor.isFinishedIn(KeyguardState.GONE), keyguardTransitionInteractor.isInTransition( Edge.create(to = Scenes.Gone), Edge.create(to = KeyguardState.GONE), ) )) .isFalse() ), ) { finishedInGone, transitioningToGone -> !finishedInGone && !transitioningToGone } }, "keyguardNotGoneOrTransitioningToGone", "keyguardNotGoneAndNotTransitioningToGone", ), Pair( keyguardTransitionInteractor Loading @@ -427,19 +433,19 @@ constructor( "deviceNotTransitioningToAsleepState", ), Pair( keyguardInteractor.isSecureCameraActive .isFalse() .or( alternateBouncerInteractor.isVisible.or( combine( keyguardInteractor.isSecureCameraActive, alternateBouncerInteractor.isVisible, if (SceneContainerFlag.isEnabled) { sceneInteractor.get().transitionState.map { it.isIdle(overlay = Overlays.Bouncer) } } else { keyguardInteractor.primaryBouncerShowing } ) ), }, ) { isSecureCameraActive, alternateBouncerVisible, primaryBouncerShowing -> !isSecureCameraActive || alternateBouncerVisible || primaryBouncerShowing }, "secureCameraNotActiveOrAnyBouncerIsShowing", ), Pair( Loading @@ -452,10 +458,10 @@ constructor( ), Pair(keyguardRepository.isKeyguardShowing, "isKeyguardShowing"), Pair( userRepository.selectedUser .map { it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS } .isFalse(), "userSwitchingInProgress", userRepository.selectedUser.map { it.selectionStatus != SelectionStatus.SELECTION_IN_PROGRESS }, "userSwitchingNotInProgress", ), ) } Loading Loading @@ -769,14 +775,6 @@ constructor( } } /** Combine two boolean flows by and-ing both of them */ private fun and(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) = flow.combine(anotherFlow) { a, b -> a && b } /** Combine two boolean flows by or-ing both of them */ private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) = this.combine(anotherFlow) { a, b -> a || b } /** "Not" the given flow. The return [Flow] will be true when [this] flow is false. */ private fun Flow<Boolean>.isFalse(): Flow<Boolean> { return this.map { !it } Loading
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt +46 −34 Original line number Diff line number Diff line Loading @@ -188,7 +188,7 @@ constructor( private val devicePolicyChangedForAllUsers = broadcastDispatcher.broadcastFlow( filter = IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), user = UserHandle.ALL user = UserHandle.ALL, ) private val isFingerprintEnrolled: Flow<Boolean> = Loading @@ -199,13 +199,13 @@ constructor( override fun onEnrollmentsChanged( sensorBiometricType: BiometricType, userId: Int, hasEnrollments: Boolean hasEnrollments: Boolean, ) { if (sensorBiometricType.isFingerprint && userId == currentUserId) { trySendWithFailureLogging( hasEnrollments, TAG, "update fpEnrollment" "update fpEnrollment", ) } } Loading @@ -214,7 +214,7 @@ constructor( trySendWithFailureLogging( authController.isFingerprintEnrolled(currentUserId), TAG, "Initial value of fingerprint enrollment" "Initial value of fingerprint enrollment", ) awaitClose { authController.removeCallback(callback) } } Loading @@ -228,13 +228,13 @@ constructor( override fun onEnrollmentsChanged( sensorBiometricType: BiometricType, userId: Int, hasEnrollments: Boolean hasEnrollments: Boolean, ) { if (sensorBiometricType == BiometricType.FACE) { trySendWithFailureLogging( authController.isFaceAuthEnrolled(selectedUserId), TAG, "Face enrollment changed" "Face enrollment changed", ) } } Loading @@ -243,7 +243,7 @@ constructor( trySendWithFailureLogging( authController.isFaceAuthEnrolled(selectedUserId), TAG, "Initial value of face auth enrollment" "Initial value of face auth enrollment", ) awaitClose { authController.removeCallback(callback) } } Loading Loading @@ -327,8 +327,8 @@ constructor( SharingStarted.Eagerly, strongAuthTracker.isBiometricAllowedForUser( true, userRepository.getSelectedUserInfo().id ) userRepository.getSelectedUserInfo().id, ), ) private val isNonStrongBiometricAllowed: StateFlow<Boolean> = Loading @@ -337,8 +337,8 @@ constructor( SharingStarted.Eagerly, strongAuthTracker.isBiometricAllowedForUser( false, userRepository.getSelectedUserInfo().id ) userRepository.getSelectedUserInfo().id, ), ) private val isFingerprintBiometricAllowed: Flow<Boolean> = Loading @@ -363,33 +363,47 @@ constructor( } override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean> = isFingerprintEnrolled .and(isFingerprintEnabledForCurrentUser) .and(isFingerprintEnabledByDevicePolicy) combine( isFingerprintEnrolled, isFingerprintEnabledForCurrentUser, isFingerprintEnabledByDevicePolicy, ) { enrolled, enabledForCurrentUser, devicePolicyEnabled -> enrolled && enabledForCurrentUser && devicePolicyEnabled } .stateIn(scope, SharingStarted.Eagerly, false) override val isFingerprintAuthCurrentlyAllowed: StateFlow<Boolean> = isFingerprintEnrolledAndEnabled .and(isFingerprintBiometricAllowed) combine(isFingerprintEnrolledAndEnabled, isFingerprintBiometricAllowed) { enrolledAndEnabled, allowed -> enrolledAndEnabled && allowed } .stateIn(scope, SharingStarted.Eagerly, false) override val isFaceAuthEnrolledAndEnabled: StateFlow<Boolean> = isFaceAuthenticationEnabled .and(isFaceEnrolled) .and(mobileConnectionsRepository.isAnySimSecure.isFalse()) combine( isFaceAuthenticationEnabled, isFaceEnrolled, mobileConnectionsRepository.isAnySimSecure, ) { enabled, enrolled, isAnySimSecure -> enabled && enrolled && !isAnySimSecure } .stateIn(scope, SharingStarted.Eagerly, false) override val isFaceAuthCurrentlyAllowed: Flow<Boolean> = isFaceAuthEnrolledAndEnabled .and(isFaceBiometricsAllowed) .and(isFaceAuthSupportedInCurrentPosture) combine( isFaceAuthEnrolledAndEnabled, isFaceBiometricsAllowed, isFaceAuthSupportedInCurrentPosture, ) { enrolledAndEnabled, allowed, supportedInCurrentPosture -> enrolledAndEnabled && allowed && supportedInCurrentPosture } } private class StrongAuthTracker( private val userRepository: UserRepository, @ShadeDisplayAware context: Context? ) : LockPatternUtils.StrongAuthTracker(context) { @ShadeDisplayAware context: Context?, ) : LockPatternUtils.StrongAuthTracker(context) { private val selectedUserId = userRepository.selectedUserInfo.map { it.id }.distinctUntilChanged() Loading Loading @@ -418,8 +432,8 @@ private class StrongAuthTracker( /** isNonStrongBiometricAllowed for the current user. */ val isNonStrongBiometricAllowed: Flow<Boolean> = selectedUserId .flatMapLatest { userId -> combine( selectedUserId.flatMapLatest { userId -> _nonStrongBiometricAllowed .filter { it.first == userId } .map { it.second } Loading @@ -427,8 +441,11 @@ private class StrongAuthTracker( Log.d(TAG, "isNonStrongBiometricAllowed changed for current user: $it") } .onStart { emit(isNonStrongBiometricAllowedAfterIdleTimeout(userId)) } }, isStrongBiometricAllowed, ) { nonStrongBiometricAllowed, strongBiometricAllowed -> nonStrongBiometricAllowed && strongBiometricAllowed } .and(isStrongBiometricAllowed) private val currentUserId get() = userRepository.getSelectedUserInfo().id Loading @@ -454,8 +471,3 @@ private fun DevicePolicyManager.isFingerprintDisabled(userId: Int): Boolean = private fun DevicePolicyManager.isNotActive(userId: Int, policy: Int): Boolean = (getKeyguardDisabledFeatures(null, userId) and policy) == 0 private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>): Flow<Boolean> = this.combine(anotherFlow) { a, b -> a && b } private fun Flow<Boolean>.isFalse(): Flow<Boolean> = this.map { !it }