Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60954bed authored by Beverly's avatar Beverly
Browse files

Remove biometric chained combine operators

Chained combine operators unnecessarily begin
extra coroutines. It's better to combine
the flows at one time rather than
chain them.

Test: device builds
Test: atest DeviceEntryFaceAuthRepositoryTest
Flag: EXEMPT bugfix
Fixes: 396736084
Change-Id: I334f65a36fa588befe34460a2c1fba38164065b6
parent 2723c553
Loading
Loading
Loading
Loading
+50 −52
Original line number Diff line number Diff line
@@ -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",
                    ),
                )
@@ -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",
@@ -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
@@ -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(
@@ -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",
            ),
        )
    }
@@ -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 }
+46 −34
Original line number Diff line number Diff line
@@ -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> =
@@ -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",
                                )
                            }
                        }
@@ -214,7 +214,7 @@ constructor(
                trySendWithFailureLogging(
                    authController.isFingerprintEnrolled(currentUserId),
                    TAG,
                    "Initial value of fingerprint enrollment"
                    "Initial value of fingerprint enrollment",
                )
                awaitClose { authController.removeCallback(callback) }
            }
@@ -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",
                                )
                            }
                        }
@@ -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) }
            }
@@ -327,8 +327,8 @@ constructor(
            SharingStarted.Eagerly,
            strongAuthTracker.isBiometricAllowedForUser(
                true,
                userRepository.getSelectedUserInfo().id
            )
                userRepository.getSelectedUserInfo().id,
            ),
        )

    private val isNonStrongBiometricAllowed: StateFlow<Boolean> =
@@ -337,8 +337,8 @@ constructor(
            SharingStarted.Eagerly,
            strongAuthTracker.isBiometricAllowedForUser(
                false,
                userRepository.getSelectedUserInfo().id
            )
                userRepository.getSelectedUserInfo().id,
            ),
        )

    private val isFingerprintBiometricAllowed: Flow<Boolean> =
@@ -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()
@@ -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 }
@@ -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
@@ -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 }