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

Commit 3d053532 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Biometric auth keyguard adjustments

- During passive authentication, the keyguard should not be dismissed
because the user might be looking at notifications.
- Keyguard should still be dismissed if bouncer was visible.
- Some sensors are allowed to trigger biometrics auth

Change-Id: Iff492c5e1eb807ab3b9b187a376c4db975606b5a
Fixes: 123581946
Fixes: 123364930
Test: fake bio unlock from (lock screen, bouncer)
Test: fingerprint unlock from LS, bouncer, AOD
Test: atest BiometricsUnlockControllerTest
Test: atest StatusBarTest
Test: atest KeyguardUpdateMonitorTest
parent fdf43845
Loading
Loading
Loading
Loading
+45 −19
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.function.Consumer;

/**
 * Watches for updates that may be interesting to the keyguard, and provides
@@ -218,7 +219,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    // Battery status
    private BatteryStatus mBatteryStatus;

    private final StrongAuthTracker mStrongAuthTracker;
    @VisibleForTesting
    protected StrongAuthTracker mStrongAuthTracker;

    private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
            mCallbacks = Lists.newArrayList();
@@ -344,8 +346,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
                    handleUserUnlocked();
                    break;
                case MSG_ASSISTANT_STACK_CHANGED:
                    mAssistantVisible = (boolean)msg.obj;
                    updateBiometricListeningState();
                    setAssistantVisible((boolean) msg.obj);
                    break;
                case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
                    updateBiometricListeningState();
@@ -538,7 +539,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    }

    private void onFingerprintAuthenticated(int userId) {
    @VisibleForTesting
    protected void onFingerprintAuthenticated(int userId) {
        Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated");
        mUserFingerprintAuthenticated.put(userId, true);
        // Update/refresh trust state only if user can skip bouncer
@@ -693,7 +695,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    }

    private void onFaceAuthenticated(int userId) {
    @VisibleForTesting
    protected void onFaceAuthenticated(int userId) {
        Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated");
        mUserFaceAuthenticated.put(userId, true);
        // Update/refresh trust state only if user can skip bouncer
@@ -898,8 +901,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {


    public boolean getUserCanSkipBouncer(int userId) {
        return getUserHasTrust(userId) || (mUserFingerprintAuthenticated.get(userId)
                && isUnlockingWithBiometricAllowed());
        boolean fingerprintOrFace = mUserFingerprintAuthenticated.get(userId)
                || mUserFaceAuthenticated.get(userId);
        return getUserHasTrust(userId) || (fingerprintOrFace && isUnlockingWithBiometricAllowed());
    }

    public boolean getUserHasTrust(int userId) {
@@ -950,6 +954,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    }

    @VisibleForTesting
    void setAssistantVisible(boolean assistantVisible) {
        mAssistantVisible = assistantVisible;
        updateBiometricListeningState();
    }

    static class DisplayClientState {
        public int clientGeneration;
        public boolean clearing;
@@ -1047,7 +1057,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    };

    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
    @VisibleForTesting
    protected final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
@@ -1121,7 +1132,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    };

    private FaceManager.AuthenticationCallback mFaceAuthenticationCallback
    @VisibleForTesting
    FaceManager.AuthenticationCallback mFaceAuthenticationCallback
            = new FaceManager.AuthenticationCallback() {

        @Override
@@ -1298,9 +1310,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    }

    public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
        public StrongAuthTracker(Context context) {
    public static class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
        private final Consumer<Integer> mStrongAuthRequiredChangedCallback;

        public StrongAuthTracker(Context context,
                Consumer<Integer> strongAuthRequiredChangedCallback) {
            super(context);
            mStrongAuthRequiredChangedCallback = strongAuthRequiredChangedCallback;
        }

        public boolean isUnlockingWithBiometricAllowed() {
@@ -1316,7 +1332,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {

        @Override
        public void onStrongAuthRequiredChanged(int userId) {
            notifyStrongAuthStateChanged(userId);
            mStrongAuthRequiredChangedCallback.accept(userId);
        }
    }

@@ -1423,7 +1439,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        mContext = context;
        mSubscriptionManager = SubscriptionManager.from(context);
        mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
        mStrongAuthTracker = new StrongAuthTracker(context);
        mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);

        // Since device can't be un-provisioned, we only need to register a content observer
        // to update mDeviceProvisioned when we are...
@@ -1548,6 +1564,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    }

    /**
     * Request passive authentication, when sensors detect that a user might be present.
     */
    public void onAuthInterruptDetected() {
        if (DEBUG) Log.d(TAG, "onAuthInterruptDetected()");
        updateFaceListeningState();
    }

    private void updateFaceListeningState() {
        // If this message exists, we should not authenticate again until this message is
        // consumed by the handler
@@ -1585,11 +1609,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    }

    private boolean shouldListenForFace() {
        return (mKeyguardIsVisible || !mDeviceInteractive ||
                (mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
                shouldListenForFaceAssistant() || (mKeyguardOccluded && mIsDreaming))
                && !mSwitchingUser && !isFaceDisabled(getCurrentUser())
                && !mKeyguardGoingAway && !mFaceLockedOut && mFaceSettingEnabledForUser;
        final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep;
        final int user = getCurrentUser();

        return (mBouncer || awakeKeyguard || shouldListenForFaceAssistant())
                && !mSwitchingUser && !getUserCanSkipBouncer(user) && !isFaceDisabled(user)
                && !mKeyguardGoingAway && !mFaceLockedOut && mFaceSettingEnabledForUser
                && mUserManager.isUserUnlocked(user);
    }


+7 −7
Original line number Diff line number Diff line
@@ -35,19 +35,19 @@ public class DozeLog {
    private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
    static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");

    private static final int REASONS = 10;
    public static final int REASONS = 10;

    public static final int PULSE_REASON_NONE = -1;
    public static final int PULSE_REASON_INTENT = 0;
    public static final int PULSE_REASON_NOTIFICATION = 1;
    public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
    public static final int PULSE_REASON_SENSOR_PICKUP = 3;
    public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
    public static final int REASON_SENSOR_PICKUP = 3;
    public static final int REASON_SENSOR_DOUBLE_TAP = 4;
    public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
    public static final int PULSE_REASON_DOCKING = 6;
    public static final int REASON_SENSOR_WAKE_UP = 7;
    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
    public static final int PULSE_REASON_SENSOR_TAP = 9;
    public static final int REASON_SENSOR_TAP = 9;

    private static boolean sRegisterKeyguardCallback = true;

@@ -202,13 +202,13 @@ public class DozeLog {
            case PULSE_REASON_INTENT: return "intent";
            case PULSE_REASON_NOTIFICATION: return "notification";
            case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
            case PULSE_REASON_SENSOR_PICKUP: return "pickup";
            case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
            case REASON_SENSOR_PICKUP: return "pickup";
            case REASON_SENSOR_DOUBLE_TAP: return "doubletap";
            case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
            case PULSE_REASON_DOCKING: return "docking";
            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
            case REASON_SENSOR_WAKE_UP: return "wakeup";
            case PULSE_REASON_SENSOR_TAP: return "tap";
            case REASON_SENSOR_TAP: return "tap";
            default: throw new IllegalArgumentException("bad reason: " + pulseReason);
        }
    }
+4 −4
Original line number Diff line number Diff line
@@ -97,20 +97,20 @@ public class DozeSensors {
                        mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
                        Settings.Secure.DOZE_PICK_UP_GESTURE,
                        config.dozePickupSensorAvailable(),
                        DozeLog.PULSE_REASON_SENSOR_PICKUP, false /* touchCoords */,
                        DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
                        false /* touchscreen */),
                new TriggerSensor(
                        findSensorWithType(config.doubleTapSensorType()),
                        Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
                        true /* configured */,
                        DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
                        DozeLog.REASON_SENSOR_DOUBLE_TAP,
                        dozeParameters.doubleTapReportsTouchCoordinates(),
                        true /* touchscreen */),
                new TriggerSensor(
                        findSensorWithType(config.tapSensorType()),
                        Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
                        true /* configured */,
                        DozeLog.PULSE_REASON_SENSOR_TAP,
                        DozeLog.REASON_SENSOR_TAP,
                        false /* reports touch coordinates */,
                        true /* touchscreen */),
                new TriggerSensor(
@@ -530,7 +530,7 @@ public class DozeSensors {

        /**
         * Called when a sensor requests a pulse
         * @param pulseReason Requesting sensor, e.g. {@link DozeLog#PULSE_REASON_SENSOR_PICKUP}
         * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
         * @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
         * @param screenX the location on the screen where the sensor fired or -1
 *                if the sensor doesn't support reporting screen locations.
+3 −7
Original line number Diff line number Diff line
@@ -108,10 +108,6 @@ public class DozeTriggers implements DozeMachine.Part {
        DozeLog.traceNotificationPulse(mContext);
    }

    private void onWhisper() {
        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
    }

    private void proximityCheckThenCall(IntConsumer callback,
            boolean alreadyPerformedProxCheck,
            int reason) {
@@ -137,9 +133,9 @@ public class DozeTriggers implements DozeMachine.Part {
    @VisibleForTesting
    void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
            float screenX, float screenY, float[] rawValues) {
        boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
        boolean isTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_TAP;
        boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
        boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP;
        boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP;
        boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP;
        boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
        boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
        boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
+27 −24
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
    private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";

    /**
     * Mode in which we don't need to wake up the device when we get a fingerprint.
     * Mode in which we don't need to wake up the device when we authenticate.
     */
    public static final int MODE_NONE = 0;

@@ -70,8 +70,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
    public static final int MODE_SHOW_BOUNCER = 3;

    /**
     * Mode in which we only wake up the device, and keyguard was not showing when we acquired a
     * fingerprint.
     * Mode in which we only wake up the device, and keyguard was not showing when we authenticated.
     * */
    public static final int MODE_ONLY_WAKE = 4;

@@ -96,22 +95,21 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
     */
    private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;

    private final NotificationMediaManager mMediaManager =
            Dependency.get(NotificationMediaManager.class);
    private PowerManager mPowerManager;
    private Handler mHandler = new Handler();
    private final NotificationMediaManager mMediaManager;
    private final PowerManager mPowerManager;
    private final Handler mHandler;
    private PowerManager.WakeLock mWakeLock;
    private KeyguardUpdateMonitor mUpdateMonitor;
    private final KeyguardUpdateMonitor mUpdateMonitor;
    private final UnlockMethodCache mUnlockMethodCache;
    private final StatusBarWindowController mStatusBarWindowController;
    private final Context mContext;
    private final int mWakeUpDelay;
    private int mMode;
    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    private StatusBarWindowController mStatusBarWindowController;
    private DozeScrimController mDozeScrimController;
    private KeyguardViewMediator mKeyguardViewMediator;
    private ScrimController mScrimController;
    private StatusBar mStatusBar;
    private final UnlockMethodCache mUnlockMethodCache;
    private final Context mContext;
    private final int mWakeUpDelay;
    private int mPendingAuthenticatedUserId = -1;
    private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
    private boolean mPendingShowBouncer;
@@ -122,11 +120,14 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
                                     KeyguardViewMediator keyguardViewMediator,
                                     ScrimController scrimController,
                                     StatusBar statusBar,
                                     UnlockMethodCache unlockMethodCache) {
                                     UnlockMethodCache unlockMethodCache, Handler handler,
                                     KeyguardUpdateMonitor keyguardUpdateMonitor,
                                     int wakeUpDelay) {
        mContext = context;
        mPowerManager = context.getSystemService(PowerManager.class);
        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
        mUpdateMonitor = keyguardUpdateMonitor;
        mUpdateMonitor.registerCallback(this);
        mMediaManager = Dependency.get(NotificationMediaManager.class);
        Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
        Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver);
        mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
@@ -135,8 +136,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
        mScrimController = scrimController;
        mStatusBar = statusBar;
        mUnlockMethodCache = unlockMethodCache;
        mWakeUpDelay = context.getResources().getInteger(
                com.android.internal.R.integer.config_wakeUpDelayDoze);
        mHandler = handler;
        mWakeUpDelay = wakeUpDelay;
    }

    public void setStatusBarKeyguardViewManager(
@@ -206,7 +207,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
            Trace.endSection();
            return;
        }
        startWakeAndUnlock(calculateMode());
        startWakeAndUnlock(calculateMode(biometricSourceType));
    }

    public void startWakeAndUnlock(int mode) {
@@ -295,7 +296,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
    }

    private void showBouncer() {
        if (calculateMode() == MODE_SHOW_BOUNCER) {
        if (mMode == MODE_SHOW_BOUNCER) {
            mStatusBarKeyguardViewManager.showBouncer(false);
        }
        mStatusBarKeyguardViewManager.animateCollapsePanels(
@@ -339,29 +340,30 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
        return mMode;
    }

    private int calculateMode() {
    private int calculateMode(BiometricSourceType biometricSourceType) {
        boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
        boolean deviceDreaming = mUpdateMonitor.isDreaming();
        boolean isFace = biometricSourceType == BiometricSourceType.FACE;

        if (!mUpdateMonitor.isDeviceInteractive()) {
            if (!mStatusBarKeyguardViewManager.isShowing()) {
                return MODE_ONLY_WAKE;
            } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
                return MODE_WAKE_AND_UNLOCK_PULSING;
                return isFace ? MODE_NONE : MODE_WAKE_AND_UNLOCK_PULSING;
            } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
                return MODE_WAKE_AND_UNLOCK;
            } else {
                return MODE_SHOW_BOUNCER;
            }
        }
        if (unlockingAllowed && deviceDreaming) {
        if (unlockingAllowed && deviceDreaming && !isFace) {
            return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
        }
        if (mStatusBarKeyguardViewManager.isShowing()) {
            if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) {
                return MODE_DISMISS_BOUNCER;
            } else if (unlockingAllowed) {
                return MODE_UNLOCK;
                return isFace ? MODE_ONLY_WAKE : MODE_UNLOCK;
            } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
                return MODE_SHOW_BOUNCER;
            }
@@ -437,7 +439,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
    }

    /**
     * Successful authentication with fingerprint that wakes up the device.
     * Successful authentication with fingerprint, face, or iris that wakes up the device.
     */
    public boolean isWakeAndUnlock() {
        return mMode == MODE_WAKE_AND_UNLOCK
@@ -446,7 +448,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
    }

    /**
     * Successful authentication with fingerprint when the screen was either on or off.
     * Successful authentication with fingerprint, face, or iris when the screen was either
     * on or off.
     */
    public boolean isBiometricUnlock() {
        return isWakeAndUnlock() || mMode == MODE_UNLOCK;
Loading