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

Commit 864ea0da authored by Beverly's avatar Beverly
Browse files

Add FingerprintAuthenticationStatus

Update DeviceEntryFingerprintAuthRepository.isLockedOut
StateFlow to only start sharing when subscribed, instead
of Eagerly. This was causing issues with testing & it isn't necessary
to start sharing eagerly.

Test: atest DeviceEntryFaceAuthRepositoryTest DeviceEntryFingerprintAuthRepositoryTest
KeyguardFaceAuthInteractorTest
Bug: 288308594

Change-Id: I57b1fef035e477818face0f4f47eae9f132c04d0
parent f0ba4ff1
Loading
Loading
Loading
Loading
+22 −18
Original line number Diff line number Diff line
@@ -164,13 +164,13 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent;
import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.AuthenticationStatus;
import com.android.systemui.keyguard.shared.model.DetectionStatus;
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.AcquiredFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus;
import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.WeatherData;
@@ -1471,27 +1471,31 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private FaceAuthenticationListener mFaceAuthenticationListener =
            new FaceAuthenticationListener() {
                @Override
                public void onAuthenticationStatusChanged(@NonNull AuthenticationStatus status) {
                    if (status instanceof AcquiredAuthenticationStatus) {
                public void onAuthenticationStatusChanged(
                        @NonNull FaceAuthenticationStatus status
                ) {
                    if (status instanceof AcquiredFaceAuthenticationStatus) {
                        handleFaceAcquired(
                                ((AcquiredAuthenticationStatus) status).getAcquiredInfo());
                    } else if (status instanceof ErrorAuthenticationStatus) {
                        ErrorAuthenticationStatus error = (ErrorAuthenticationStatus) status;
                                ((AcquiredFaceAuthenticationStatus) status).getAcquiredInfo());
                    } else if (status instanceof ErrorFaceAuthenticationStatus) {
                        ErrorFaceAuthenticationStatus error =
                                (ErrorFaceAuthenticationStatus) status;
                        handleFaceError(error.getMsgId(), error.getMsg());
                    } else if (status instanceof FailedAuthenticationStatus) {
                    } else if (status instanceof FailedFaceAuthenticationStatus) {
                        handleFaceAuthFailed();
                    } else if (status instanceof HelpAuthenticationStatus) {
                        HelpAuthenticationStatus helpMsg = (HelpAuthenticationStatus) status;
                    } else if (status instanceof HelpFaceAuthenticationStatus) {
                        HelpFaceAuthenticationStatus helpMsg =
                                (HelpFaceAuthenticationStatus) status;
                        handleFaceHelp(helpMsg.getMsgId(), helpMsg.getMsg());
                    } else if (status instanceof SuccessAuthenticationStatus) {
                    } else if (status instanceof SuccessFaceAuthenticationStatus) {
                        FaceManager.AuthenticationResult result =
                                ((SuccessAuthenticationStatus) status).getSuccessResult();
                                ((SuccessFaceAuthenticationStatus) status).getSuccessResult();
                        handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
                    }
                }

                @Override
                public void onDetectionStatusChanged(@NonNull DetectionStatus status) {
                public void onDetectionStatusChanged(@NonNull FaceDetectionStatus status) {
                    handleFaceAuthenticated(status.getUserId(), status.isStrongBiometric());
                }
            };
+3 −3
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

package com.android.systemui.bouncer.domain.interactor

import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.SystemClock
@@ -35,8 +35,8 @@ constructor(
    private val keyguardStateController: KeyguardStateController,
    private val bouncerRepository: KeyguardBouncerRepository,
    private val biometricSettingsRepository: BiometricSettingsRepository,
    private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
    private val systemClock: SystemClock,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
) {
    var receivedDownTouch = false
    val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
@@ -78,7 +78,7 @@ constructor(
            biometricSettingsRepository.isFingerprintEnrolled.value &&
            biometricSettingsRepository.isStrongBiometricAllowed.value &&
            biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
            !deviceEntryFingerprintAuthRepository.isLockedOut.value &&
            !keyguardUpdateMonitor.isFingerprintLockedOut &&
            !keyguardStateController.isUnlocked &&
            !statusBarStateController.isDozing
    }
+19 −19
Original line number Diff line number Diff line
@@ -38,13 +38,13 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
import com.android.systemui.keyguard.shared.model.AcquiredFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.log.SessionTracker
@@ -88,10 +88,10 @@ interface DeviceEntryFaceAuthRepository {
    val canRunFaceAuth: StateFlow<Boolean>

    /** Provide the current status of face authentication. */
    val authenticationStatus: Flow<AuthenticationStatus>
    val authenticationStatus: Flow<FaceAuthenticationStatus>

    /** Provide the current status of face detection. */
    val detectionStatus: Flow<DetectionStatus>
    val detectionStatus: Flow<FaceDetectionStatus>

    /** Current state of whether face authentication is locked out or not. */
    val isLockedOut: StateFlow<Boolean>
@@ -151,13 +151,13 @@ constructor(
    private var cancelNotReceivedHandlerJob: Job? = null
    private var halErrorRetryJob: Job? = null

    private val _authenticationStatus: MutableStateFlow<AuthenticationStatus?> =
    private val _authenticationStatus: MutableStateFlow<FaceAuthenticationStatus?> =
        MutableStateFlow(null)
    override val authenticationStatus: Flow<AuthenticationStatus>
    override val authenticationStatus: Flow<FaceAuthenticationStatus>
        get() = _authenticationStatus.filterNotNull()

    private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null)
    override val detectionStatus: Flow<DetectionStatus>
    private val _detectionStatus = MutableStateFlow<FaceDetectionStatus?>(null)
    override val detectionStatus: Flow<FaceDetectionStatus>
        get() = _detectionStatus.filterNotNull()

    private val _isLockedOut = MutableStateFlow(false)
@@ -396,18 +396,18 @@ constructor(
    private val faceAuthCallback =
        object : FaceManager.AuthenticationCallback() {
            override fun onAuthenticationFailed() {
                _authenticationStatus.value = FailedAuthenticationStatus
                _authenticationStatus.value = FailedFaceAuthenticationStatus
                _isAuthenticated.value = false
                faceAuthLogger.authenticationFailed()
                onFaceAuthRequestCompleted()
            }

            override fun onAuthenticationAcquired(acquireInfo: Int) {
                _authenticationStatus.value = AcquiredAuthenticationStatus(acquireInfo)
                _authenticationStatus.value = AcquiredFaceAuthenticationStatus(acquireInfo)
            }

            override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
                val errorStatus = ErrorAuthenticationStatus(errorCode, errString.toString())
                val errorStatus = ErrorFaceAuthenticationStatus(errorCode, errString.toString())
                if (errorStatus.isLockoutError()) {
                    _isLockedOut.value = true
                }
@@ -433,11 +433,11 @@ constructor(
                if (faceAcquiredInfoIgnoreList.contains(code)) {
                    return
                }
                _authenticationStatus.value = HelpAuthenticationStatus(code, helpStr.toString())
                _authenticationStatus.value = HelpFaceAuthenticationStatus(code, helpStr.toString())
            }

            override fun onAuthenticationSucceeded(result: FaceManager.AuthenticationResult) {
                _authenticationStatus.value = SuccessAuthenticationStatus(result)
                _authenticationStatus.value = SuccessFaceAuthenticationStatus(result)
                _isAuthenticated.value = true
                faceAuthLogger.faceAuthSuccess(result)
                onFaceAuthRequestCompleted()
@@ -482,7 +482,7 @@ constructor(
    private val detectionCallback =
        FaceManager.FaceDetectionCallback { sensorId, userId, isStrong ->
            faceAuthLogger.faceDetected()
            _detectionStatus.value = DetectionStatus(sensorId, userId, isStrong)
            _detectionStatus.value = FaceDetectionStatus(sensorId, userId, isStrong)
        }

    private var cancellationInProgress = false
+100 −17
Original line number Diff line number Diff line
@@ -21,27 +21,29 @@ import android.hardware.biometrics.BiometricAuthenticator.Modality
import android.hardware.biometrics.BiometricSourceType
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Dumpable
import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import java.io.PrintWriter
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailedFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn

/** Encapsulates state about device entry fingerprint auth mechanism. */
interface DeviceEntryFingerprintAuthRepository {
    /** Whether the device entry fingerprint auth is locked out. */
    val isLockedOut: StateFlow<Boolean>
    val isLockedOut: Flow<Boolean>

    /**
     * Whether the fingerprint sensor is currently listening, this doesn't mean that the user is
@@ -53,6 +55,9 @@ interface DeviceEntryFingerprintAuthRepository {
     * Fingerprint sensor type present on the device, null if fingerprint sensor is not available.
     */
    val availableFpSensorType: Flow<BiometricType?>

    /** Provide the current status of fingerprint authentication. */
    val authenticationStatus: Flow<FingerprintAuthenticationStatus>
}

/**
@@ -69,16 +74,7 @@ constructor(
    val authController: AuthController,
    val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    @Application scope: CoroutineScope,
    dumpManager: DumpManager,
) : DeviceEntryFingerprintAuthRepository, Dumpable {

    init {
        dumpManager.registerDumpable(this)
    }

    override fun dump(pw: PrintWriter, args: Array<String?>) {
        pw.println("isLockedOut=${isLockedOut.value}")
    }
) : DeviceEntryFingerprintAuthRepository {

    override val availableFpSensorType: Flow<BiometricType?>
        get() {
@@ -114,7 +110,7 @@ constructor(
        else if (authController.isRearFpsSupported) BiometricType.REAR_FINGERPRINT else null
    }

    override val isLockedOut: StateFlow<Boolean> =
    override val isLockedOut: Flow<Boolean> =
        conflatedCallbackFlow {
                val sendLockoutUpdate =
                    fun() {
@@ -138,7 +134,7 @@ constructor(
                sendLockoutUpdate()
                awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
            }
            .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false)
            .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)

    override val isRunning: Flow<Boolean>
        get() = conflatedCallbackFlow {
@@ -166,6 +162,93 @@ constructor(
            awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
        }

    override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
        get() = conflatedCallbackFlow {
            val callback =
                object : KeyguardUpdateMonitorCallback() {
                    override fun onBiometricAuthenticated(
                        userId: Int,
                        biometricSourceType: BiometricSourceType,
                        isStrongBiometric: Boolean,
                    ) {

                        sendUpdateIfFingerprint(
                            biometricSourceType,
                            SuccessFingerprintAuthenticationStatus(
                                userId,
                                isStrongBiometric,
                            ),
                        )
                    }

                    override fun onBiometricError(
                        msgId: Int,
                        errString: String?,
                        biometricSourceType: BiometricSourceType,
                    ) {
                        sendUpdateIfFingerprint(
                            biometricSourceType,
                            ErrorFingerprintAuthenticationStatus(
                                msgId,
                                errString,
                            ),
                        )
                    }

                    override fun onBiometricHelp(
                        msgId: Int,
                        helpString: String?,
                        biometricSourceType: BiometricSourceType,
                    ) {
                        sendUpdateIfFingerprint(
                            biometricSourceType,
                            HelpFingerprintAuthenticationStatus(
                                msgId,
                                helpString,
                            ),
                        )
                    }

                    override fun onBiometricAuthFailed(
                        biometricSourceType: BiometricSourceType,
                    ) {
                        sendUpdateIfFingerprint(
                            biometricSourceType,
                            FailedFingerprintAuthenticationStatus,
                        )
                    }

                    override fun onBiometricAcquired(
                        biometricSourceType: BiometricSourceType,
                        acquireInfo: Int,
                    ) {
                        sendUpdateIfFingerprint(
                            biometricSourceType,
                            AcquiredFingerprintAuthenticationStatus(
                                acquireInfo,
                            ),
                        )
                    }

                    private fun sendUpdateIfFingerprint(
                        biometricSourceType: BiometricSourceType,
                        authenticationStatus: FingerprintAuthenticationStatus
                    ) {
                        if (biometricSourceType != BiometricSourceType.FINGERPRINT) {
                            return
                        }

                        trySendWithFailureLogging(
                            authenticationStatus,
                            TAG,
                            "new fingerprint authentication status"
                        )
                    }
                }
            keyguardUpdateMonitor.registerCallback(callback)
            awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
        }

    companion object {
        const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
    }
+4 −4
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ package com.android.systemui.keyguard.data.repository

import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -40,10 +40,10 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
    private val _canRunFaceAuth = MutableStateFlow(false)
    override val canRunFaceAuth: StateFlow<Boolean> = _canRunFaceAuth

    override val authenticationStatus: Flow<AuthenticationStatus>
    override val authenticationStatus: Flow<FaceAuthenticationStatus>
        get() = emptyFlow()

    override val detectionStatus: Flow<DetectionStatus>
    override val detectionStatus: Flow<FaceDetectionStatus>
        get() = emptyFlow()

    private val _isLockedOut = MutableStateFlow(false)
Loading