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

Commit 6aeeac2d authored by Beverly's avatar Beverly
Browse files

Only show trustAgentErrors when biometrics aren't engaged

Fixes: 308716806
Flag: None bugfix
Test: atest KeyguardIndicationControllerWithCoroutinesTest KeyguardIndicationControllerTest
Change-Id: I66549771ced0c13d305a55451f542724b5658a98
parent b519f3be
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