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

Commit c733abde authored by Beverly's avatar Beverly
Browse files

Update FP failure logic when device is unlocked

* Update strings when fingerprint auth fails
when the device is already unlocked (by face auth or
a TrustAgent). Instead of telling the user fingerprint failed,
instead tell the user why the device is unlocked and how
to enter the device (ie: Unlocked by Face, Swipe up to open)
* If fingerprint gets locked out while face (nonbypass) or a
TrustAgent is keeping the device unlocked - don't allow the user
to use the face or TrustAgent trust to enter the device. Instead,
require primary authentication to enter the device on fingerprint
lockout.

Test: atest KeyguardUpdateMonitorTest KeyguardIndicationControllerTest
Fixes: 265443040
Change-Id: Ibe89cb8703fdf82f4f3f22c556b32fd9fcc3b2c8
parent d2fe4b9e
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -108,7 +108,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
@@ -1311,7 +1310,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    }

    public boolean getUserHasTrust(int userId) {
        return !isTrustDisabled() && mUserHasTrust.get(userId);
        return !isTrustDisabled() && mUserHasTrust.get(userId)
                && isUnlockingWithTrustAgentAllowed();
    }

    /**
@@ -1319,12 +1319,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     */
    public boolean getUserUnlockedWithBiometric(int userId) {
        BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
        BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
        boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
                && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
        boolean faceAllowed = face != null && face.mAuthenticated
        return fingerprintAllowed || getUserUnlockedWithFace(userId);
    }


    /**
     * Returns whether the user is unlocked with face.
     */
    public boolean getUserUnlockedWithFace(int userId) {
        BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
        return face != null && face.mAuthenticated
                && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
        return fingerprintAllowed || faceAllowed;
    }

    /**
@@ -1399,6 +1406,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        return mUserTrustIsUsuallyManaged.get(userId);
    }

    private boolean isUnlockingWithTrustAgentAllowed() {
        return isUnlockingWithBiometricAllowed(true);
    }

    public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
        // StrongAuthTracker#isUnlockingWithBiometricAllowed includes
        // STRONG_AUTH_REQUIRED_AFTER_LOCKOUT which is the same as mFingerprintLockedOutPermanent;
+39 −18
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE;

import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
@@ -539,6 +540,10 @@ public class KeyguardIndicationController {
                            .build(),
                    true
            );
        } else {
            mRotateTextViewController.hideIndication(
                    INDICATION_TYPE_BIOMETRIC_MESSAGE);
        }
        if (!TextUtils.isEmpty(mBiometricMessageFollowUp)) {
            mRotateTextViewController.updateIndication(
                    INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
@@ -553,10 +558,6 @@ public class KeyguardIndicationController {
            mRotateTextViewController.hideIndication(
                    INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
        }
        } else {
            mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE);
            mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
        }
    }

    private void updateTransient() {
@@ -784,7 +785,8 @@ public class KeyguardIndicationController {
     */
    private void showBiometricMessage(CharSequence biometricMessage,
            @Nullable CharSequence biometricMessageFollowUp) {
        if (TextUtils.equals(biometricMessage, mBiometricMessage)) {
        if (TextUtils.equals(biometricMessage, mBiometricMessage)
                && TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) {
            return;
        }

@@ -793,7 +795,8 @@ public class KeyguardIndicationController {

        mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
        hideBiometricMessageDelayed(
                mBiometricMessageFollowUp != null
                !TextUtils.isEmpty(mBiometricMessage)
                        && !TextUtils.isEmpty(mBiometricMessageFollowUp)
                        ? IMPORTANT_MSG_MIN_DURATION * 2
                        : DEFAULT_HIDE_DELAY_MS
        );
@@ -1091,6 +1094,8 @@ public class KeyguardIndicationController {
                    && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
            final boolean faceAuthFailed = biometricSourceType == FACE
                    && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed
            final boolean fpAuthFailed = biometricSourceType == FINGERPRINT
                    && msgId == BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; // ran matcher & failed
            final boolean isUnlockWithFingerprintPossible = canUnlockWithFingerprint();
            final boolean isCoExFaceAcquisitionMessage =
                    faceAuthSoftError && isUnlockWithFingerprintPossible;
@@ -1113,6 +1118,22 @@ public class KeyguardIndicationController {
                            mContext.getString(R.string.keyguard_face_failed),
                            mContext.getString(R.string.keyguard_suggest_fingerprint)
                    );
                } else if (fpAuthFailed
                        && mKeyguardUpdateMonitor.getUserUnlockedWithFace(getCurrentUser())) {
                    // 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(
                            mContext.getString(R.string.keyguard_face_successful_unlock),
                            mContext.getString(R.string.keyguard_unlock)
                    );
                } else if (fpAuthFailed
                        && mKeyguardUpdateMonitor.getUserHasTrust(
                                KeyguardUpdateMonitor.getCurrentUser())) {
                    showBiometricMessage(
                            getTrustGrantedIndication(),
                            mContext.getString(R.string.keyguard_unlock)
                    );
                } else {
                    showBiometricMessage(helpString);
                }
+5 −0
Original line number Diff line number Diff line
@@ -437,6 +437,11 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
            update(false /* updateAlways */);
        }

        @Override
        public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) {
            update(false /* updateAlways */);
        }

        @Override
        public void onKeyguardVisibilityChanged(boolean visible) {
            update(false /* updateAlways */);
+25 −1
Original line number Diff line number Diff line
@@ -685,11 +685,35 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        // WHEN fingerprint is locked out
        fingerprintErrorLockedOut();

        // THEN unlocking with fingeprint is not allowed
        // THEN unlocking with fingerprint is not allowed
        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
                BiometricSourceType.FINGERPRINT));
    }

    @Test
    public void trustAgentHasTrust() {
        // WHEN user has trust
        mKeyguardUpdateMonitor.onTrustChanged(true, true, getCurrentUser(), 0, null);

        // THEN user is considered as "having trust" and bouncer can be skipped
        Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
        Assert.assertTrue(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()));
    }

    @Test
    public void trustAgentHasTrust_fingerprintLockout() {
        // GIVEN user has trust
        mKeyguardUpdateMonitor.onTrustChanged(true, true, getCurrentUser(), 0, null);
        Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));

        // WHEN fingerprint is locked out
        fingerprintErrorLockedOut();

        // THEN user is NOT considered as "having trust" and bouncer cannot be skipped
        Assert.assertFalse(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
        Assert.assertFalse(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()));
    }

    @Test
    public void testTriesToAuthenticate_whenBouncer() {
        setKeyguardBouncerVisibility(true);
+76 −0
Original line number Diff line number Diff line
@@ -619,6 +619,82 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
                mContext.getString(R.string.keyguard_suggest_fingerprint));
    }

    @Test
    public void onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked() {
        createController();

        // GIVEN face has already unlocked the device
        when(mKeyguardUpdateMonitor.getUserUnlockedWithFace(anyInt())).thenReturn(true);

        String message = "A message";
        mController.setVisible(true);

        // WHEN there's a fingerprint not recognized message
        mController.getKeyguardCallback().onBiometricHelp(
                BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
                message,
                BiometricSourceType.FINGERPRINT);

        // THEN show sequential messages such as: 'Unlocked by face' and
        // 'Swipe up to open'
        verifyIndicationMessage(
                INDICATION_TYPE_BIOMETRIC_MESSAGE,
                mContext.getString(R.string.keyguard_face_successful_unlock));
        verifyIndicationMessage(
                INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
                mContext.getString(R.string.keyguard_unlock));
    }

    @Test
    public void onBiometricHelp_coEx_fpFailure_trustAgentAlreadyUnlocked() {
        createController();

        // GIVEN trust agent has already unlocked the device
        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);

        String message = "A message";
        mController.setVisible(true);

        // WHEN there's a fingerprint not recognized message
        mController.getKeyguardCallback().onBiometricHelp(
                BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
                message,
                BiometricSourceType.FINGERPRINT);

        // THEN show sequential messages such as: 'Kept unlocked by TrustAgent' and
        // 'Swipe up to open'
        verifyIndicationMessage(
                INDICATION_TYPE_BIOMETRIC_MESSAGE,
                mContext.getString(R.string.keyguard_indication_trust_unlocked));
        verifyIndicationMessage(
                INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
                mContext.getString(R.string.keyguard_unlock));
    }

    @Test
    public void onBiometricHelp_coEx_fpFailure_trustAgentUnlocked_emptyTrustGrantedMessage() {
        createController();

        // GIVEN trust agent has already unlocked the device & trust granted message is empty
        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
        mController.showTrustGrantedMessage(false, "");

        String message = "A message";
        mController.setVisible(true);

        // WHEN there's a fingerprint not recognized message
        mController.getKeyguardCallback().onBiometricHelp(
                BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
                message,
                BiometricSourceType.FINGERPRINT);

        // THEN show action to unlock (ie: 'Swipe up to open')
        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
        verifyIndicationMessage(
                INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
                mContext.getString(R.string.keyguard_unlock));
    }

    @Test
    public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromError() {
        createController();