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

Commit 3bdab009 authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

Add active unlock trigger

Posts a notification the request for active unlock would
trigger. To enable this feature: use the Flag Flipper app and
enable Active Unlock.

Change-Id: I53d2e869f168ffd04125e0430ccb9e40c1f69c1b
Test: manual
Bug: 192405661
Bug: 213631396
parent 4b10475f
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,4 +17,5 @@
<resources>
<resources>
    <bool name="kg_show_ime_at_screen_on">true</bool>
    <bool name="kg_show_ime_at_screen_on">true</bool>
    <bool name="kg_use_all_caps">true</bool>
    <bool name="kg_use_all_caps">true</bool>
    <bool name="flag_active_unlock">false</bool>
</resources>
</resources>
+16 −0
Original line number Original line Diff line number Diff line
@@ -64,3 +64,19 @@ data class KeyguardFaceListenModel(
    val secureCameraLaunched: Boolean,
    val secureCameraLaunched: Boolean,
    val switchingUser: Boolean
    val switchingUser: Boolean
) : KeyguardListenModel()
) : KeyguardListenModel()
/**
 * Verbose debug information associated with [KeyguardUpdateMonitor.shouldTriggerActiveUnlock].
 */
data class KeyguardActiveUnlockModel(
    @CurrentTimeMillisLong override val timeMillis: Long,
    override val userId: Int,
    override val listening: Boolean,
    // keep sorted
    val authInterruptActive: Boolean,
    val encryptedOrTimedOut: Boolean,
    val fpLockout: Boolean,
    val lockDown: Boolean,
    val switchingUser: Boolean,
    val triggerActiveUnlockForAssistant: Boolean,
    val userCanDismissLockScreen: Boolean
) : KeyguardListenModel()
+7 −1
Original line number Original line Diff line number Diff line
@@ -32,15 +32,17 @@ class KeyguardListenQueue(
) {
) {
    private val faceQueue = ArrayDeque<KeyguardFaceListenModel>()
    private val faceQueue = ArrayDeque<KeyguardFaceListenModel>()
    private val fingerprintQueue = ArrayDeque<KeyguardFingerprintListenModel>()
    private val fingerprintQueue = ArrayDeque<KeyguardFingerprintListenModel>()
    private val activeUnlockQueue = ArrayDeque<KeyguardActiveUnlockModel>()


    @get:VisibleForTesting val models: List<KeyguardListenModel>
    @get:VisibleForTesting val models: List<KeyguardListenModel>
        get() = faceQueue + fingerprintQueue
        get() = faceQueue + fingerprintQueue + activeUnlockQueue


    /** Push a [model] to the queue (will be logged until the queue exceeds [sizePerModality]). */
    /** Push a [model] to the queue (will be logged until the queue exceeds [sizePerModality]). */
    fun add(model: KeyguardListenModel) {
    fun add(model: KeyguardListenModel) {
        val queue = when (model) {
        val queue = when (model) {
            is KeyguardFaceListenModel -> faceQueue.apply { add(model) }
            is KeyguardFaceListenModel -> faceQueue.apply { add(model) }
            is KeyguardFingerprintListenModel -> fingerprintQueue.apply { add(model) }
            is KeyguardFingerprintListenModel -> fingerprintQueue.apply { add(model) }
            is KeyguardActiveUnlockModel -> activeUnlockQueue.apply { add(model) }
        }
        }


        if (queue.size > sizePerModality) {
        if (queue.size > sizePerModality) {
@@ -63,5 +65,9 @@ class KeyguardListenQueue(
        for (model in fingerprintQueue) {
        for (model in fingerprintQueue) {
            writer.println(stringify(model))
            writer.println(stringify(model))
        }
        }
        writer.println("  Active unlock triggers (last ${activeUnlockQueue.size} calls):")
        for (model in activeUnlockQueue) {
            writer.println(stringify(model))
        }
    }
    }
}
}
+119 −1
Original line number Original line Diff line number Diff line
@@ -37,6 +37,8 @@ import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.AlarmManager;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.app.UserSwitchObserver;
import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager;
@@ -102,6 +104,8 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -109,6 +113,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.Assert;
import com.android.systemui.util.NotificationChannels;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.RingerModeTracker;


import com.google.android.collect.Lists;
import com.google.android.collect.Lists;
@@ -143,8 +148,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
    private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
    private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
    private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
    private static final boolean DEBUG_FINGERPRINT = Build.IS_DEBUGGABLE;
    private static final boolean DEBUG_FINGERPRINT = Build.IS_DEBUGGABLE;
    private static final boolean DEBUG_ACTIVE_UNLOCK = Build.IS_DEBUGGABLE;
    private static final boolean DEBUG_SPEW = false;
    private static final boolean DEBUG_SPEW = false;
    private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
    private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
    private int mNumActiveUnlockTriggers = 0;


    private static final String ACTION_FACE_UNLOCK_STARTED
    private static final String ACTION_FACE_UNLOCK_STARTED
            = "com.android.facelock.FACE_UNLOCK_STARTED";
            = "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -334,6 +341,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    private final Executor mBackgroundExecutor;
    private final Executor mBackgroundExecutor;
    private SensorPrivacyManager mSensorPrivacyManager;
    private SensorPrivacyManager mSensorPrivacyManager;
    private FeatureFlags mFeatureFlags;
    private int mFaceAuthUserId;
    private int mFaceAuthUserId;


    /**
    /**
@@ -1311,6 +1319,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    void setAssistantVisible(boolean assistantVisible) {
    void setAssistantVisible(boolean assistantVisible) {
        mAssistantVisible = assistantVisible;
        mAssistantVisible = assistantVisible;
        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
        if (mAssistantVisible) {
            requestActiveUnlock();
        }
    }
    }


    static class DisplayClientState {
    static class DisplayClientState {
@@ -1650,6 +1661,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
        Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
        Assert.isMainThread();
        Assert.isMainThread();
        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
        requestActiveUnlock();
        for (int i = 0; i < mCallbacks.size(); i++) {
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
            if (cb != null) {
@@ -1777,7 +1789,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
            AuthController authController,
            AuthController authController,
            TelephonyListenerManager telephonyListenerManager,
            TelephonyListenerManager telephonyListenerManager,
            InteractionJankMonitor interactionJankMonitor,
            InteractionJankMonitor interactionJankMonitor,
            LatencyTracker latencyTracker) {
            LatencyTracker latencyTracker,
            FeatureFlags featureFlags) {
        mContext = context;
        mContext = context;
        mSubscriptionManager = SubscriptionManager.from(context);
        mSubscriptionManager = SubscriptionManager.from(context);
        mTelephonyListenerManager = telephonyListenerManager;
        mTelephonyListenerManager = telephonyListenerManager;
@@ -1795,6 +1808,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        mAuthController = authController;
        mAuthController = authController;
        dumpManager.registerDumpable(getClass().getName(), this);
        dumpManager.registerDumpable(getClass().getName(), this);
        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
        mFeatureFlags = featureFlags;


        mHandler = new Handler(mainLooper) {
        mHandler = new Handler(mainLooper) {
            @Override
            @Override
@@ -2180,6 +2194,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }
        }
        mAuthInterruptActive = active;
        mAuthInterruptActive = active;
        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
        requestActiveUnlock();
    }
    }


    /**
    /**
@@ -2228,6 +2243,97 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }
        }
    }
    }


    /**
     * Attempts to trigger active unlock.
     */
    public void requestActiveUnlock() {
        // If this message exists, FP has already authenticated, so wait until that is handled
        if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
            return;
        }

        if (shouldTriggerActiveUnlock() && mFeatureFlags.isEnabled(Flags.ACTIVE_UNLOCK)) {
            // TODO (b/192405661): call new TrustManager API
            mNumActiveUnlockTriggers++;
            Log.d("ActiveUnlock", "would have triggered times=" + mNumActiveUnlockTriggers);
            showActiveUnlockNotification(mNumActiveUnlockTriggers);
        }
    }

    /**
     * TODO (b/192405661): Only for testing. Remove before release.
     */
    private void showActiveUnlockNotification(int times) {
        final String message = "Active unlock triggered "  + times + " times.";
        final Notification.Builder nb =
                new Notification.Builder(mContext, NotificationChannels.GENERAL)
                        .setSmallIcon(R.drawable.ic_volume_ringer)
                        .setContentTitle(message)
                        .setStyle(new Notification.BigTextStyle().bigText(message));
        mContext.getSystemService(NotificationManager.class).notifyAsUser(
                "active_unlock",
                0,
                nb.build(),
                UserHandle.ALL);
    }

    private boolean shouldTriggerActiveUnlock() {
        // TODO: check if active unlock is ENABLED / AVAILABLE

        // Triggers:
        final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
        final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
                && mStatusBarState != StatusBarState.SHADE_LOCKED;

        // Gates:
        final int user = getCurrentUser();

        // No need to trigger active unlock if we're already unlocked or don't have
        // pin/pattern/password setup
        final boolean userCanDismissLockScreen = getUserCanSkipBouncer(user)
                || !mLockPatternUtils.isSecure(user);

        // Don't trigger active unlock if fp is locked out TODO: confirm this one
        final boolean fpLockedout = mFingerprintLockedOut || mFingerprintLockedOutPermanent;

        // Don't trigger active unlock if primary auth is required
        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
        final boolean isLockDown =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
        final boolean isEncryptedOrTimedOut =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);

        final boolean shouldTriggerActiveUnlock =
                (mAuthInterruptActive || triggerActiveUnlockForAssistant || awakeKeyguard)
                        && !mSwitchingUser
                        && !userCanDismissLockScreen
                        && !fpLockedout
                        && !isLockDown
                        && !isEncryptedOrTimedOut
                        && !mKeyguardGoingAway
                        && !mSecureCameraLaunched;

        // Aggregate relevant fields for debug logging.
        if (DEBUG_ACTIVE_UNLOCK || DEBUG_SPEW) {
            maybeLogListenerModelData(
                    new KeyguardActiveUnlockModel(
                            System.currentTimeMillis(),
                            user,
                            shouldTriggerActiveUnlock,
                            mAuthInterruptActive,
                            isEncryptedOrTimedOut,
                            fpLockedout,
                            isLockDown,
                            mSwitchingUser,
                            triggerActiveUnlockForAssistant,
                            userCanDismissLockScreen));
        }

        return shouldTriggerActiveUnlock;
    }

    private boolean shouldListenForFingerprintAssistant() {
    private boolean shouldListenForFingerprintAssistant() {
        BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(getCurrentUser());
        BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(getCurrentUser());
        return mAssistantVisible && mKeyguardOccluded
        return mAssistantVisible && mKeyguardOccluded
@@ -2242,6 +2348,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                && !mUserHasTrust.get(getCurrentUser(), false);
                && !mUserHasTrust.get(getCurrentUser(), false);
    }
    }


    private boolean shouldTriggerActiveUnlockForAssistant() {
        return mAssistantVisible && mKeyguardOccluded
                && !mUserHasTrust.get(getCurrentUser(), false);
    }

    @VisibleForTesting
    @VisibleForTesting
    protected boolean shouldListenForFingerprint(boolean isUdfps) {
    protected boolean shouldListenForFingerprint(boolean isUdfps) {
        final int user = getCurrentUser();
        final int user = getCurrentUser();
@@ -2406,6 +2517,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
            Log.v(TAG, model.toString());
            Log.v(TAG, model.toString());
        }
        }


        if (DEBUG_ACTIVE_UNLOCK
                && model instanceof KeyguardActiveUnlockModel
                && model.getListening()) {
            mListenModels.add(model);
            return;
        }

        // Add model data to the historical buffer.
        // Add model data to the historical buffer.
        final boolean notYetRunning =
        final boolean notYetRunning =
                (DEBUG_FACE
                (DEBUG_FACE
+3 −0
Original line number Original line Diff line number Diff line
@@ -74,6 +74,9 @@ public class Flags {
    public static final ResourceBooleanFlag BOUNCER_USER_SWITCHER =
    public static final ResourceBooleanFlag BOUNCER_USER_SWITCHER =
            new ResourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher);
            new ResourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher);


    public static final ResourceBooleanFlag ACTIVE_UNLOCK =
            new ResourceBooleanFlag(205, R.bool.flag_active_unlock);

    /***************************************/
    /***************************************/
    // 300 - power menu
    // 300 - power menu
    public static final BooleanFlag POWER_MENU_LITE =
    public static final BooleanFlag POWER_MENU_LITE =
Loading