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

Commit 053fd082 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Don't show face messages if fp messages are showing" into main

parents d91903a2 8e989f9f
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -18,11 +18,16 @@ package com.android.keyguard;

import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.hardware.biometrics.BiometricSourceType;
import android.os.SystemClock;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Pair;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -39,6 +44,16 @@ import javax.inject.Inject;
 */
public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
        extends ViewController<T> {
    /**
     * Pair representing:
     *   first - BiometricSource the currently displayed message is associated with.
     *   second - Timestamp the biometric message came in uptimeMillis.
     * This Pair can be null if the message is not associated with a biometric.
     */
    @Nullable
    private Pair<BiometricSourceType, Long> mMessageBiometricSource = null;
    private static final Long SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS = 3500L;

    /**
     * Delay before speaking an accessibility announcement. Used to prevent
     * lift-to-type from interrupting itself.
@@ -149,12 +164,42 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
     * Sets a message to the underlying text view.
     */
    public void setMessage(CharSequence s, boolean animate) {
        setMessage(s, animate, null);
    }

    /**
     * Sets a message to the underlying text view.
     */
    public void setMessage(CharSequence s, BiometricSourceType biometricSourceType) {
        setMessage(s, true, biometricSourceType);
    }

    private void setMessage(
            CharSequence s,
            boolean animate,
            BiometricSourceType biometricSourceType) {
        final long uptimeMillis = SystemClock.uptimeMillis();
        if (skipShowingFaceMessage(biometricSourceType, uptimeMillis)) {
            Log.d("KeyguardMessageAreaController", "Skip showing face message \"" + s + "\"");
            return;
        }
        mMessageBiometricSource =  new Pair<>(biometricSourceType, uptimeMillis);
        if (mView.isDisabled()) {
            return;
        }
        mView.setMessage(s, animate);
    }

    private boolean skipShowingFaceMessage(
            BiometricSourceType biometricSourceType, Long currentUptimeMillis
    ) {
        return mMessageBiometricSource != null
                && biometricSourceType == BiometricSourceType.FACE
                && mMessageBiometricSource.first == BiometricSourceType.FINGERPRINT
                && (currentUptimeMillis - mMessageBiometricSource.second)
                    < SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS;
    }

    public void setMessage(int resId) {
        String message = resId != 0 ? mView.getResources().getString(resId) : null;
        setMessage(message);
+21 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

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
@@ -117,6 +118,26 @@ constructor(
        )
    }

    fun logDropNonFingerprintMessage(
        message: CharSequence,
        followUpMessage: CharSequence?,
        biometricSourceType: BiometricSourceType?,
    ) {
        buffer.log(
            KeyguardIndicationController.TAG,
            LogLevel.DEBUG,
            {
                str1 = message.toString()
                str2 = followUpMessage?.toString()
                str3 = biometricSourceType?.name
            },
            {
                "droppingNonFingerprintMessage message=$str1 " +
                    "followUpMessage:$str2 biometricSourceType:$str3"
            }
        )
    }

    fun logUpdateBatteryIndication(
        powerIndication: String,
        pluggedIn: Boolean,
+110 −41
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import android.os.UserManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
@@ -187,6 +188,7 @@ public class KeyguardIndicationController {
    private CharSequence mTransientIndication;
    private CharSequence mBiometricMessage;
    private CharSequence mBiometricMessageFollowUp;
    private BiometricSourceType mBiometricMessageSource;
    protected ColorStateList mInitialTextColorState;
    private boolean mVisible;
    private boolean mOrganizationOwnedDevice;
@@ -206,7 +208,7 @@ public class KeyguardIndicationController {
    private int mBatteryLevel;
    private boolean mBatteryPresent = true;
    private long mChargingTimeRemaining;
    private String mBiometricErrorMessageToShowOnScreenOn;
    private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn;
    private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
    private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral;
    private boolean mInited;
@@ -225,15 +227,18 @@ public class KeyguardIndicationController {
                mIsActiveDreamLockscreenHosted = isLockscreenHosted;
                updateDeviceEntryIndication(false);
            };
    private final ScreenLifecycle.Observer mScreenObserver =
            new ScreenLifecycle.Observer() {
    private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
        @Override
        public void onScreenTurnedOn() {
            mHandler.removeMessages(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON);
            if (mBiometricErrorMessageToShowOnScreenOn != null) {
                String followUpMessage = mFaceLockedOutThisAuthSession
                        ? faceLockedOutFollowupMessage() : null;
                showBiometricMessage(mBiometricErrorMessageToShowOnScreenOn, followUpMessage);
                showBiometricMessage(
                        mBiometricErrorMessageToShowOnScreenOn.first,
                        followUpMessage,
                        mBiometricErrorMessageToShowOnScreenOn.second
                );
                // We want to keep this message around in case the screen was off
                hideBiometricMessageDelayed(DEFAULT_HIDE_DELAY_MS);
                mBiometricErrorMessageToShowOnScreenOn = null;
@@ -879,8 +884,35 @@ public class KeyguardIndicationController {
        updateTransient();
    }

    private void showBiometricMessage(CharSequence biometricMessage) {
        showBiometricMessage(biometricMessage, null);
    private void showSuccessBiometricMessage(
            CharSequence biometricMessage,
            @Nullable CharSequence biometricMessageFollowUp,
            BiometricSourceType biometricSourceType
    ) {
        showBiometricMessage(biometricMessage, biometricMessageFollowUp, biometricSourceType, true);
    }

    private void showSuccessBiometricMessage(CharSequence biometricMessage,
            BiometricSourceType biometricSourceType) {
        showSuccessBiometricMessage(biometricMessage, null, biometricSourceType);
    }

    private void showBiometricMessage(CharSequence biometricMessage,
            BiometricSourceType biometricSourceType) {
        showBiometricMessage(biometricMessage, null, biometricSourceType, false);
    }

    private void showBiometricMessage(
            CharSequence biometricMessage,
            @Nullable CharSequence biometricMessageFollowUp,
            BiometricSourceType biometricSourceType
    ) {
        showBiometricMessage(
                biometricMessage,
                biometricMessageFollowUp,
                biometricSourceType,
                false
        );
    }

    /**
@@ -889,15 +921,33 @@ public class KeyguardIndicationController {
     * by {@link KeyguardIndicationRotateTextViewController}, see class for rotating message
     * logic.
     */
    private void showBiometricMessage(CharSequence biometricMessage,
            @Nullable CharSequence biometricMessageFollowUp) {
    private void showBiometricMessage(
            CharSequence biometricMessage,
            @Nullable CharSequence biometricMessageFollowUp,
            BiometricSourceType biometricSourceType,
            boolean isSuccessMessage
    ) {
        if (TextUtils.equals(biometricMessage, mBiometricMessage)
                && biometricSourceType == mBiometricMessageSource
                && TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) {
            return;
        }

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

        mBiometricMessage = biometricMessage;
        mBiometricMessageFollowUp = biometricMessageFollowUp;
        mBiometricMessageSource = biometricSourceType;

        mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
        hideBiometricMessageDelayed(
@@ -914,6 +964,7 @@ public class KeyguardIndicationController {
        if (mBiometricMessage != null || mBiometricMessageFollowUp != null) {
            mBiometricMessage = null;
            mBiometricMessageFollowUp = null;
            mBiometricMessageSource = null;
            mHideBiometricMessageHandler.cancel();
            updateBiometricMessage();
        }
@@ -1085,7 +1136,8 @@ public class KeyguardIndicationController {
                } else {
                    message = mContext.getString(R.string.keyguard_retry);
                }
                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState);
                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState,
                        null);
            }
        } else {
            final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(
@@ -1097,34 +1149,40 @@ public class KeyguardIndicationController {
                        || mAccessibilityManager.isTouchExplorationEnabled();
                if (udfpsSupported && faceAuthenticated) { // co-ex
                    if (a11yEnabled) {
                        showBiometricMessage(
                        showSuccessBiometricMessage(
                                mContext.getString(R.string.keyguard_face_successful_unlock),
                                mContext.getString(R.string.keyguard_unlock)
                                mContext.getString(R.string.keyguard_unlock),
                                FACE
                        );
                    } else {
                        showBiometricMessage(
                        showSuccessBiometricMessage(
                                mContext.getString(R.string.keyguard_face_successful_unlock),
                                mContext.getString(R.string.keyguard_unlock_press)
                                mContext.getString(R.string.keyguard_unlock_press),
                                FACE
                        );
                    }
                } else if (faceAuthenticated) { // face-only
                    showBiometricMessage(
                    showSuccessBiometricMessage(
                            mContext.getString(R.string.keyguard_face_successful_unlock),
                            mContext.getString(R.string.keyguard_unlock)
                            mContext.getString(R.string.keyguard_unlock),
                            FACE
                    );
                } else if (udfpsSupported) { // udfps-only
                    if (a11yEnabled) {
                        showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
                        showSuccessBiometricMessage(
                                mContext.getString(R.string.keyguard_unlock),
                                null
                        );
                    } else {
                        showBiometricMessage(mContext.getString(
                                R.string.keyguard_unlock_press));
                        showSuccessBiometricMessage(mContext.getString(
                                R.string.keyguard_unlock_press), null);
                    }
                } else { // no security or unlocked by a trust agent
                    showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
                    showSuccessBiometricMessage(mContext.getString(R.string.keyguard_unlock), null);
                }
            } else {
                // suggest swiping up for the primary authentication bouncer
                showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
                showBiometricMessage(mContext.getString(R.string.keyguard_unlock), null);
            }
        }
    }
@@ -1245,49 +1303,55 @@ public class KeyguardIndicationController {
                    mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString);
                }
                mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
                        mInitialTextColorState);
                        mInitialTextColorState, biometricSourceType);
            } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
                    showBiometricMessage(
                            helpString,
                            mContext.getString(R.string.keyguard_suggest_fingerprint)
                            mContext.getString(R.string.keyguard_suggest_fingerprint),
                            biometricSourceType
                    );
                } else if (faceAuthFailed && isUnlockWithFingerprintPossible) {
                    showBiometricMessage(
                            mContext.getString(R.string.keyguard_face_failed),
                            mContext.getString(R.string.keyguard_suggest_fingerprint)
                            mContext.getString(R.string.keyguard_suggest_fingerprint),
                            biometricSourceType
                    );
                } else if (fpAuthFailed
                        && mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()) {
                    // face had already previously unlocked the device, so instead of showing a
                    // fingerprint error, tell them they have already unlocked with face auth
                    // and how to enter their device
                    showBiometricMessage(
                    showSuccessBiometricMessage(
                            mContext.getString(R.string.keyguard_face_successful_unlock),
                            mContext.getString(R.string.keyguard_unlock)
                            mContext.getString(R.string.keyguard_unlock),
                            null
                    );
                } else if (fpAuthFailed
                        && mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())) {
                    showBiometricMessage(
                    showSuccessBiometricMessage(
                            getTrustGrantedIndication(),
                            mContext.getString(R.string.keyguard_unlock)
                            mContext.getString(R.string.keyguard_unlock),
                            null
                    );
                } else if (faceAuthUnavailable) {
                    showBiometricMessage(
                            helpString,
                            isUnlockWithFingerprintPossible
                                    ? mContext.getString(R.string.keyguard_suggest_fingerprint)
                                    : mContext.getString(R.string.keyguard_unlock)
                                    : mContext.getString(R.string.keyguard_unlock),
                            biometricSourceType
                    );
                } else {
                    showBiometricMessage(helpString);
                    showBiometricMessage(helpString, biometricSourceType);
                }
            } else if (faceAuthFailed) {
                // show action to unlock
                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
                        TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
            } else {
                mBiometricErrorMessageToShowOnScreenOn = helpString;
                mBiometricErrorMessageToShowOnScreenOn =
                        new Pair<>(helpString, biometricSourceType);
                mHandler.sendMessageDelayed(
                        mHandler.obtainMessage(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON),
                        1000);
@@ -1333,7 +1397,7 @@ public class KeyguardIndicationController {
            } else if (mIndicationHelper.isFaceLockoutErrorMsg(msgId)) {
                handleFaceLockoutError(errString);
            } else {
                showErrorMessageNowOrLater(errString, null);
                showErrorMessageNowOrLater(errString, null, FACE);
            }
        }

@@ -1343,7 +1407,7 @@ public class KeyguardIndicationController {
                        msgId,
                        errString);
            } else {
                showErrorMessageNowOrLater(errString, null);
                showErrorMessageNowOrLater(errString, null, FINGERPRINT);
            }
        }

@@ -1371,7 +1435,7 @@ public class KeyguardIndicationController {

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

        @Override
@@ -1459,12 +1523,13 @@ public class KeyguardIndicationController {
        // had too many unsuccessful attempts.
        if (!mFaceLockedOutThisAuthSession) {
            mFaceLockedOutThisAuthSession = true;
            showErrorMessageNowOrLater(errString, followupMessage);
            showErrorMessageNowOrLater(errString, followupMessage, FACE);
        } else if (!mAuthController.isUdfpsFingerDown()) {
            // On subsequent lockouts, we show a more generic locked out message.
            showErrorMessageNowOrLater(
                    mContext.getString(R.string.keyguard_face_unlock_unavailable),
                    followupMessage);
                    followupMessage,
                    FACE);
        }
    }

@@ -1484,7 +1549,8 @@ public class KeyguardIndicationController {
                    && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
                showBiometricMessage(
                        deferredFaceMessage,
                        mContext.getString(R.string.keyguard_suggest_fingerprint)
                        mContext.getString(R.string.keyguard_suggest_fingerprint),
                        FACE
                );
            } else {
                // otherwise, don't show any message
@@ -1496,7 +1562,8 @@ public class KeyguardIndicationController {
            // user to manually retry.
            showBiometricMessage(
                    deferredFaceMessage,
                    mContext.getString(R.string.keyguard_unlock)
                    mContext.getString(R.string.keyguard_unlock),
                    FACE
            );
        } else {
            // Face-only
@@ -1510,13 +1577,15 @@ public class KeyguardIndicationController {
                getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed();
    }

    private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg) {
    private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg,
            BiometricSourceType biometricSourceType) {
        if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
            mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState);
            mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState,
                    biometricSourceType);
        } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
            showBiometricMessage(errString, followUpMsg);
            showBiometricMessage(errString, followUpMsg, biometricSourceType);
        } else {
            mBiometricErrorMessageToShowOnScreenOn = errString;
            mBiometricErrorMessageToShowOnScreenOn = new Pair<>(errString, biometricSourceType);
        }
    }

+4 −3
Original line number Diff line number Diff line
@@ -781,7 +781,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
                    }

                    updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
                    setKeyguardMessage(message, null);
                    setKeyguardMessage(message, null, null);
                    return;
                }

@@ -1444,11 +1444,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    }

    /** Display security message to relevant KeyguardMessageArea. */
    public void setKeyguardMessage(String message, ColorStateList colorState) {
    public void setKeyguardMessage(String message, ColorStateList colorState,
            BiometricSourceType biometricSourceType) {
        if (mAlternateBouncerInteractor.isVisibleState()) {
            if (mKeyguardMessageAreaController != null) {
                DeviceEntryUdfpsRefactor.assertInLegacyMode();
                mKeyguardMessageAreaController.setMessage(message);
                mKeyguardMessageAreaController.setMessage(message, biometricSourceType);
            }
        } else {
            mPrimaryBouncerInteractor.showMessage(message, colorState);
+50 −0
Original line number Diff line number Diff line
@@ -19,11 +19,14 @@ package com.android.keyguard;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.hardware.biometrics.BiometricSourceType;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -119,4 +122,51 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
        when(mKeyguardMessageArea.getText()).thenReturn(msg);
        assertThat(mMessageAreaController.getMessage()).isEqualTo(msg);
    }

    @Test
    public void testFingerprintMessageUpdate() {
        String msg = "fpMessage";
        mMessageAreaController.setMessage(
                msg, BiometricSourceType.FINGERPRINT
        );
        verify(mKeyguardMessageArea).setMessage(msg, /* animate= */ true);

        String msg2 = "fpMessage2";
        mMessageAreaController.setMessage(
                msg2, BiometricSourceType.FINGERPRINT
        );
        verify(mKeyguardMessageArea).setMessage(msg2, /* animate= */ true);
    }

    @Test
    public void testFaceMessageDroppedWhileFingerprintMessageShowing() {
        String fpMsg = "fpMessage";
        mMessageAreaController.setMessage(
                fpMsg, BiometricSourceType.FINGERPRINT
        );
        verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean());

        String faceMessage = "faceMessage";
        mMessageAreaController.setMessage(
                faceMessage, BiometricSourceType.FACE
        );
        verify(mKeyguardMessageArea, never())
                .setMessage(eq(faceMessage), /* animate= */ anyBoolean());
    }

    @Test
    public void testGenericMessageShowsAfterFingerprintMessageShowing() {
        String fpMsg = "fpMessage";
        mMessageAreaController.setMessage(
                fpMsg, BiometricSourceType.FINGERPRINT
        );
        verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean());

        String genericMessage = "genericMessage";
        mMessageAreaController.setMessage(
                genericMessage, null
        );
        verify(mKeyguardMessageArea)
                .setMessage(eq(genericMessage), /* animate= */ anyBoolean());
    }
}
Loading