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

Commit af80a50c authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "Only show trustAgentErrors when biometrics aren't engaged" into main

parents 3d6cbd35 6aeeac2d
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.keyguard.logging

import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
import com.android.systemui.log.LogBuffer
@@ -81,6 +80,23 @@ constructor(
        )
    }

    fun delayShowingTrustAgentError(
        msg: CharSequence,
        fpEngaged: Boolean,
        faceRunning: Boolean,
    ) {
        buffer.log(
            BIO_TAG,
            LogLevel.DEBUG,
            {
                str1 = msg.toString()
                bool1 = fpEngaged
                bool2 = faceRunning
            },
            { "Delay showing trustAgentError:$str1. fpEngaged:$bool1 faceRunning:$bool2 " }
        )
    }

    fun logUpdateDeviceEntryIndication(
        animate: Boolean,
        visible: Boolean,
@@ -118,10 +134,9 @@ constructor(
        )
    }

    fun logDropNonFingerprintMessage(
    fun logDropFaceMessage(
        message: CharSequence,
        followUpMessage: CharSequence?,
        biometricSourceType: BiometricSourceType?,
    ) {
        buffer.log(
            KeyguardIndicationController.TAG,
@@ -129,12 +144,8 @@ constructor(
            {
                str1 = message.toString()
                str2 = followUpMessage?.toString()
                str3 = biometricSourceType?.name
            },
            {
                "droppingNonFingerprintMessage message=$str1 " +
                    "followUpMessage:$str2 biometricSourceType:$str3"
            }
            { "droppingFaceMessage message=$str1 followUpMessage:$str2" }
        )
    }

+8 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest
@@ -43,9 +44,15 @@ constructor(
    biometricSettingsInteractor: DeviceEntryBiometricSettingsInteractor,
    fingerprintPropertyRepository: FingerprintPropertyRepository,
) {
    /** Whether fingerprint authentication is currently running or not */
    /**
     * Whether fingerprint authentication is currently running or not. This does not mean the user
     * [isEngaged] with the fingerprint.
     */
    val isRunning: Flow<Boolean> = repository.isRunning

    /** Whether the user is actively engaging with the fingerprint sensor */
    val isEngaged: StateFlow<Boolean> = repository.isEngaged

    /** Provide the current status of fingerprint authentication. */
    val authenticationStatus: Flow<FingerprintAuthenticationStatus> =
        repository.authenticationStatus
+18 −0
Original line number Diff line number Diff line
@@ -40,9 +40,13 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn

@@ -57,6 +61,9 @@ interface DeviceEntryFingerprintAuthRepository {
     */
    val isRunning: Flow<Boolean>

    /** Whether the fingerprint sensor is actively authenticating. */
    val isEngaged: StateFlow<Boolean>

    /**
     * Fingerprint sensor type present on the device, null if fingerprint sensor is not available.
     */
@@ -176,6 +183,17 @@ constructor(
                    mainDispatcher
                ) // keyguardUpdateMonitor requires registration on main thread.

    override val isEngaged: StateFlow<Boolean> =
        authenticationStatus
            .map { it.isEngaged }
            .filterNotNull()
            .map { it }
            .stateIn(
                scope = scope,
                started = WhileSubscribed(),
                initialValue = false,
            )

    // TODO(b/322555228) Remove after consolidating device entry auth messages with BP auth messages
    //  in BiometricStatusRepository
    /**
+25 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.shared.model
import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD
import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START
import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN
import android.hardware.fingerprint.FingerprintManager
import android.os.SystemClock.elapsedRealtime
import com.android.systemui.biometrics.shared.model.AuthenticationReason
@@ -26,26 +27,43 @@ import com.android.systemui.biometrics.shared.model.AuthenticationReason
/**
 * Fingerprint authentication status provided by
 * [com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository]
 *
 * @isEngaged whether fingerprint is actively engaged by the user. This is distinct from fingerprint
 * running on the device. Can be null if the status does not have an associated isEngaged state.
 */
sealed class FingerprintAuthenticationStatus
sealed class FingerprintAuthenticationStatus(val isEngaged: Boolean?)

/** Fingerprint authentication success status. */
data class SuccessFingerprintAuthenticationStatus(
    val userId: Int,
    val isStrongBiometric: Boolean,
) : FingerprintAuthenticationStatus()
) : FingerprintAuthenticationStatus(isEngaged = false)

/** Fingerprint authentication help message. */
data class HelpFingerprintAuthenticationStatus(
    val msgId: Int,
    val msg: String?,
) : FingerprintAuthenticationStatus()
) : FingerprintAuthenticationStatus(isEngaged = null)

/** Fingerprint acquired message. */
data class AcquiredFingerprintAuthenticationStatus(
    val authenticationReason: AuthenticationReason,
    val acquiredInfo: Int
) : FingerprintAuthenticationStatus() {
) :
    FingerprintAuthenticationStatus(
        isEngaged =
            if (acquiredInfo == FINGERPRINT_ACQUIRED_START) {
                true
            } else if (
                acquiredInfo == FINGERPRINT_ACQUIRED_UNKNOWN ||
                    acquiredInfo == FINGERPRINT_ACQUIRED_GOOD
            ) {
                null
            } else {
                // soft errors that indicate fingerprint activity ended
                false
            }
    ) {

    val fingerprintCaptureStarted: Boolean = acquiredInfo == FINGERPRINT_ACQUIRED_START

@@ -53,7 +71,8 @@ data class AcquiredFingerprintAuthenticationStatus(
}

/** Fingerprint authentication failed message. */
data object FailFingerprintAuthenticationStatus : FingerprintAuthenticationStatus()
data object FailFingerprintAuthenticationStatus :
    FingerprintAuthenticationStatus(isEngaged = false)

/** Fingerprint authentication error message */
data class ErrorFingerprintAuthenticationStatus(
@@ -61,7 +80,7 @@ data class ErrorFingerprintAuthenticationStatus(
    val msg: String? = null,
    // present to break equality check if the same error occurs repeatedly.
    val createdAt: Long = elapsedRealtime(),
) : FingerprintAuthenticationStatus() {
) : FingerprintAuthenticationStatus(isEngaged = false) {
    fun isCancellationError(): Boolean =
        msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_CANCELED ||
            msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED
+59 −10
Original line number Diff line number Diff line
@@ -98,6 +98,8 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
@@ -183,11 +185,14 @@ public class KeyguardIndicationController {
    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    private KeyguardInteractor mKeyguardInteractor;
    private final BiometricMessageInteractor mBiometricMessageInteractor;
    private DeviceEntryFingerprintAuthInteractor mDeviceEntryFingerprintAuthInteractor;
    private DeviceEntryFaceAuthInteractor mDeviceEntryFaceAuthInteractor;
    private String mPersistentUnlockMessage;
    private String mAlignmentIndication;
    private boolean mForceIsDismissible;
    private CharSequence mTrustGrantedIndication;
    private CharSequence mTransientIndication;
    private CharSequence mTrustAgentErrorMessage;
    private CharSequence mBiometricMessage;
    private CharSequence mBiometricMessageFollowUp;
    private BiometricSourceType mBiometricMessageSource;
@@ -235,6 +240,13 @@ public class KeyguardIndicationController {
    final Consumer<Set<Integer>> mCoExAcquisitionMsgIdsToShowCallback =
            (Set<Integer> coExFaceAcquisitionMsgIdsToShow) -> mCoExFaceAcquisitionMsgIdsToShow =
                    coExFaceAcquisitionMsgIdsToShow;
    @VisibleForTesting
    final Consumer<Boolean> mIsFingerprintEngagedCallback =
            (Boolean isEngaged) -> {
                if (!isEngaged) {
                    showTrustAgentErrorMessage(mTrustAgentErrorMessage);
                }
            };
    private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
        @Override
        public void onScreenTurnedOn() {
@@ -295,7 +307,9 @@ public class KeyguardIndicationController {
            FeatureFlags flags,
            IndicationHelper indicationHelper,
            KeyguardInteractor keyguardInteractor,
            BiometricMessageInteractor biometricMessageInteractor
            BiometricMessageInteractor biometricMessageInteractor,
            DeviceEntryFingerprintAuthInteractor deviceEntryFingerprintAuthInteractor,
            DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor
    ) {
        mContext = context;
        mBroadcastDispatcher = broadcastDispatcher;
@@ -325,6 +339,8 @@ public class KeyguardIndicationController {
        mIndicationHelper = indicationHelper;
        mKeyguardInteractor = keyguardInteractor;
        mBiometricMessageInteractor = biometricMessageInteractor;
        mDeviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor;
        mDeviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor;

        mFaceAcquiredMessageDeferral = faceHelpMessageDeferral.create();

@@ -409,6 +425,8 @@ public class KeyguardIndicationController {
        collectFlow(mIndicationArea,
                mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow(),
                mCoExAcquisitionMsgIdsToShowCallback);
        collectFlow(mIndicationArea, mDeviceEntryFingerprintAuthInteractor.isEngaged(),
                mIsFingerprintEngagedCallback);
    }

    /**
@@ -944,19 +962,25 @@ public class KeyguardIndicationController {

        if (!isSuccessMessage
                && mBiometricMessageSource == FINGERPRINT
                && biometricSourceType != FINGERPRINT) {
            // drop all non-fingerprint biometric messages if there's a fingerprint message showing
            mKeyguardLogger.logDropNonFingerprintMessage(
                && biometricSourceType == FACE) {
            // drop any face messages if there's a fingerprint message showing
            mKeyguardLogger.logDropFaceMessage(
                    biometricMessage,
                    biometricMessageFollowUp,
                    biometricSourceType
                    biometricMessageFollowUp
            );
            return;
        }

        if (mBiometricMessageSource != null && biometricSourceType == null) {
            // If there's a current biometric message showing and a non-biometric message
            // arrives, update the followup message with the non-biometric message.
            // Keep the biometricMessage and biometricMessageSource the same.
            mBiometricMessageFollowUp = biometricMessage;
        } else {
            mBiometricMessage = biometricMessage;
            mBiometricMessageFollowUp = biometricMessageFollowUp;
            mBiometricMessageSource = biometricSourceType;
        }

        mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
        hideBiometricMessageDelayed(
@@ -1455,7 +1479,7 @@ public class KeyguardIndicationController {

        @Override
        public void onTrustAgentErrorMessage(CharSequence message) {
            showBiometricMessage(message, null);
            showTrustAgentErrorMessage(message);
        }

        @Override
@@ -1467,6 +1491,10 @@ public class KeyguardIndicationController {
                hideBiometricMessage();
                mBiometricErrorMessageToShowOnScreenOn = null;
            }

            if (!running && biometricSourceType == FACE) {
                showTrustAgentErrorMessage(mTrustAgentErrorMessage);
            }
        }

        @Override
@@ -1533,6 +1561,25 @@ public class KeyguardIndicationController {
        return getCurrentUser() == userId;
    }

    /**
     * Only show trust agent messages after biometrics are no longer active.
     */
    private void showTrustAgentErrorMessage(CharSequence message) {
        if (message == null) {
            mTrustAgentErrorMessage = null;
            return;
        }
        boolean fpEngaged = mDeviceEntryFingerprintAuthInteractor.isEngaged().getValue();
        boolean faceRunning = mDeviceEntryFaceAuthInteractor.isRunning();
        if (fpEngaged || faceRunning) {
            mKeyguardLogger.delayShowingTrustAgentError(message, fpEngaged, faceRunning);
            mTrustAgentErrorMessage = message;
        } else {
            mTrustAgentErrorMessage = null;
            showBiometricMessage(message, null);
        }
    }

    protected void showTrustGrantedMessage(boolean dismissKeyguard, @Nullable String message) {
        mTrustGrantedIndication = message;
        updateDeviceEntryIndication(false);
@@ -1639,6 +1686,7 @@ public class KeyguardIndicationController {
            new KeyguardStateController.Callback() {
        @Override
        public void onUnlockedChanged() {
            mTrustAgentErrorMessage = null;
            updateDeviceEntryIndication(false);
        }

@@ -1649,6 +1697,7 @@ public class KeyguardIndicationController {
                mKeyguardLogger.log(TAG, LogLevel.DEBUG, "clear messages");
                mTopIndicationView.clearMessages();
                mRotateTextViewController.clearMessages();
                mTrustAgentErrorMessage = null;
            } else {
                updateDeviceEntryIndication(false);
            }
Loading