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

Commit 0dd4d731 authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "Add additional toggleable active unlock settings" into tm-dev

parents f637bd54 ba0f3d6d
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -9694,6 +9694,40 @@ public final class Settings {
        public static final String ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL =
                "active_unlock_on_biometric_fail";
        /**
         * If active unlock triggers on biometric failures, include the following error codes
         * as a biometric failure. See {@link android.hardware.biometrics.BiometricFaceConstants}.
         * Error codes should be separated by a pipe. For example: "1|4|5". If active unlock
         * should never trigger on any face errors, this should be set to an empty string.
         * A null value will use the system default value (TIMEOUT).
         * @hide
         */
        public static final String ACTIVE_UNLOCK_ON_FACE_ERRORS =
                "active_unlock_on_face_errors";
        /**
         * If active unlock triggers on biometric failures, include the following acquired info
         * as a "biometric failure". See {@link android.hardware.biometrics.BiometricFaceConstants}.
         * Acquired codes should be separated by a pipe. For example: "1|4|5". If active unlock
         * should never on trigger on any acquired info messages, this should be
         * set to an empty string. A null value will use the system default value (none).
         * @hide
         */
        public static final String ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO =
                "active_unlock_on_face_acquire_info";
        /**
         * If active unlock triggers on biometric failures, then also request active unlock on
         * unlock intent when each setting (BiometricType) is the only biometric type enrolled.
         * Biometric types should be separated by a pipe. For example: "0|3" or "0". If this
         * setting should be disabled, then this should be set to an empty string. A null value
         * will use the system default value (0 / None).
         *   0 = None, 1 = Any face, 2 = Any fingerprint, 3 = Under display fingerprint
         * @hide
         */
        public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED =
                "active_unlock_on_unlock_intent_when_biometric_enrolled";
        /**
         * Whether the assist gesture should be enabled.
         *
+3 −0
Original line number Diff line number Diff line
@@ -120,6 +120,9 @@ public class SecureSettings {
        Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
        Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
        Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
        Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
        Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
        Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
        Settings.Secure.VR_DISPLAY_MODE,
        Settings.Secure.NOTIFICATION_BADGING,
        Settings.Secure.NOTIFICATION_DISMISS_RTL,
+5 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.provider.settings.validators;

import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_PACKAGE_LIST_VALIDATOR;
@@ -176,6 +177,10 @@ public class SecureSettingsValidators {
        VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_WAKE, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS, ANY_STRING_VALIDATOR);
        VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO, ANY_STRING_VALIDATOR);
        VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
                ANY_STRING_VALIDATOR);
        VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
+172 −25
Original line number Diff line number Diff line
@@ -16,14 +16,20 @@

package com.android.keyguard

import android.annotation.IntDef
import android.content.ContentResolver
import android.database.ContentObserver
import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
@@ -44,6 +50,20 @@ class ActiveUnlockConfig @Inject constructor(
    dumpManager: DumpManager
) : Dumpable {

    companion object {
        const val TAG = "ActiveUnlockConfig"

        const val BIOMETRIC_TYPE_NONE = 0
        const val BIOMETRIC_TYPE_ANY_FACE = 1
        const val BIOMETRIC_TYPE_ANY_FINGERPRINT = 2
        const val BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT = 3
    }

    @Retention(AnnotationRetention.SOURCE)
    @IntDef(BIOMETRIC_TYPE_NONE, BIOMETRIC_TYPE_ANY_FACE, BIOMETRIC_TYPE_ANY_FINGERPRINT,
            BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT)
    annotation class BiometricType

    /**
     * Indicates the origin for an active unlock request.
     */
@@ -51,33 +71,48 @@ class ActiveUnlockConfig @Inject constructor(
        WAKE, UNLOCK_INTENT, BIOMETRIC_FAIL, ASSISTANT
    }

    var keyguardUpdateMonitor: KeyguardUpdateMonitor? = null
    private var requestActiveUnlockOnWakeup = false
    private var requestActiveUnlockOnUnlockIntent = false
    private var requestActiveUnlockOnBioFail = false

    private var faceErrorsToTriggerBiometricFailOn = mutableSetOf(FACE_ERROR_TIMEOUT)
    private var faceAcquireInfoToTriggerBiometricFailOn = mutableSetOf<Int>()
    private var onUnlockIntentWhenBiometricEnrolled = mutableSetOf<Int>(BIOMETRIC_TYPE_NONE)

    private val settingsObserver = object : ContentObserver(handler) {
        private val wakeUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
        private val unlockIntentUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)
        private val bioFailUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)
        private val wakeUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
        private val unlockIntentUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)
        private val bioFailUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)
        private val faceErrorsUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS)
        private val faceAcquireInfoUri =
                secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO)
        private val unlockIntentWhenBiometricEnrolledUri =
                secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED)

        fun register() {
            contentResolver.registerContentObserver(
            registerUri(
                    listOf(
                            wakeUri,
                    false,
                    this,
                    UserHandle.USER_ALL)
            contentResolver.registerContentObserver(
                            unlockIntentUri,
                    false,
                    this,
                    UserHandle.USER_ALL)
            contentResolver.registerContentObserver(
                            bioFailUri,
                            faceErrorsUri,
                            faceAcquireInfoUri,
                            unlockIntentWhenBiometricEnrolledUri
                    )
            )

            onChange(true, ArrayList(), 0, getCurrentUser())
        }

        private fun registerUri(uris: Collection<Uri>) {
            for (uri in uris) {
                contentResolver.registerContentObserver(
                        uri,
                        false,
                        this,
                        UserHandle.USER_ALL)

            onChange(true, ArrayList(), 0, getCurrentUser())
            }
        }

        override fun onChange(
@@ -104,6 +139,55 @@ class ActiveUnlockConfig @Inject constructor(
                requestActiveUnlockOnBioFail = secureSettings.getIntForUser(
                        ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 0, getCurrentUser()) == 1
            }

            if (selfChange || uris.contains(faceErrorsUri)) {
                processStringArray(
                        secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ERRORS,
                                getCurrentUser()),
                        faceErrorsToTriggerBiometricFailOn,
                        setOf(FACE_ERROR_TIMEOUT))
            }

            if (selfChange || uris.contains(faceAcquireInfoUri)) {
                processStringArray(
                        secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
                                getCurrentUser()),
                        faceAcquireInfoToTriggerBiometricFailOn,
                        setOf<Int>())
            }

            if (selfChange || uris.contains(unlockIntentWhenBiometricEnrolledUri)) {
                processStringArray(
                        secureSettings.getStringForUser(
                                ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
                                getCurrentUser()),
                        onUnlockIntentWhenBiometricEnrolled,
                        setOf(BIOMETRIC_TYPE_NONE))
            }
        }

        /**
         * Convert a pipe-separated set of integers into a set of ints.
         * @param stringSetting expected input are integers delineated by a pipe. For example,
         * it may look something like this: "1|5|3".
         * @param out updates the "out" Set will the integers between the pipes.
         * @param default If stringSetting is null, "out" will be populated with values in "default"
         */
        private fun processStringArray(
            stringSetting: String?,
            out: MutableSet<Int>,
            default: Set<Int>
        ) {
            out.clear()
            stringSetting?.let {
                for (code: String in stringSetting.split("|")) {
                    try {
                        out.add(code.toInt())
                    } catch (e: NumberFormatException) {
                        Log.e(TAG, "Passed an invalid setting=$code")
                    }
                }
            } ?: out.addAll(default)
        }
    }

@@ -112,6 +196,30 @@ class ActiveUnlockConfig @Inject constructor(
        dumpManager.registerDumpable(this)
    }

    /**
     * If any active unlock triggers are enabled.
     */
    fun isActiveUnlockEnabled(): Boolean {
        return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent ||
                requestActiveUnlockOnBioFail
    }

    /**
     * Whether the face error code from {@link BiometricFaceConstants} should trigger
     * active unlock on biometric failure.
     */
    fun shouldRequestActiveUnlockOnFaceError(errorCode: Int): Boolean {
        return faceErrorsToTriggerBiometricFailOn.contains(errorCode)
    }

    /**
     * Whether the face acquireInfo from {@link BiometricFaceConstants} should trigger
     * active unlock on biometric failure.
     */
    fun shouldRequestActiveUnlockOnFaceAcquireInfo(acquiredInfo: Int): Boolean {
        return faceAcquireInfoToTriggerBiometricFailOn.contains(acquiredInfo)
    }

    /**
     * Whether to trigger active unlock based on where the request is coming from and
     * the current settings.
@@ -121,7 +229,8 @@ class ActiveUnlockConfig @Inject constructor(
            ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE -> requestActiveUnlockOnWakeup

            ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT ->
                requestActiveUnlockOnUnlockIntent || requestActiveUnlockOnWakeup
                requestActiveUnlockOnUnlockIntent || requestActiveUnlockOnWakeup ||
                        (shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment())

            ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL ->
                requestActiveUnlockOnBioFail || requestActiveUnlockOnUnlockIntent ||
@@ -131,17 +240,55 @@ class ActiveUnlockConfig @Inject constructor(
        }
    }

    /**
     * If any active unlock triggers are enabled.
     */
    fun isActiveUnlockEnabled(): Boolean {
        return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent ||
                requestActiveUnlockOnBioFail
    private fun shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment(): Boolean {
        if (!requestActiveUnlockOnBioFail) {
            return false
        }

        keyguardUpdateMonitor?.let {
            val anyFaceEnrolled = it.isFaceEnrolled
            val anyFingerprintEnrolled =
                    it.getCachedIsUnlockWithFingerprintPossible(getCurrentUser())
            val udfpsEnrolled = it.isUdfpsEnrolled

            if (!anyFaceEnrolled && !anyFingerprintEnrolled) {
                return onUnlockIntentWhenBiometricEnrolled.contains(BIOMETRIC_TYPE_NONE)
            }

            if (!anyFaceEnrolled && anyFingerprintEnrolled) {
                return onUnlockIntentWhenBiometricEnrolled.contains(
                        BIOMETRIC_TYPE_ANY_FINGERPRINT) ||
                        (udfpsEnrolled && onUnlockIntentWhenBiometricEnrolled.contains(
                                BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT))
            }

            if (!anyFingerprintEnrolled && anyFaceEnrolled) {
                return onUnlockIntentWhenBiometricEnrolled.contains(BIOMETRIC_TYPE_ANY_FACE)
            }
        }

        return false
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.println("Settings:")
        pw.println("   requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup")
        pw.println("   requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent")
        pw.println("   requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail")
        pw.println("   requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" +
                "$onUnlockIntentWhenBiometricEnrolled")
        pw.println("   requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn")
        pw.println("   requestActiveUnlockOnFaceAcquireInfo=" +
                "$faceAcquireInfoToTriggerBiometricFailOn")

        pw.println("Current state:")
        keyguardUpdateMonitor?.let {
            pw.println("   shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" +
                    "${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}")
            pw.println("   faceEnrolled=${it.isFaceEnrolled}")
            pw.println("   fpEnrolled=${
                    it.getCachedIsUnlockWithFingerprintPossible(getCurrentUser())}")
            pw.println("   udfpsEnrolled=${it.isUdfpsEnrolled}")
        } ?: pw.println("   keyguardUpdateMonitor is uninitialized")
    }
}
 No newline at end of file
+23 −6
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -1615,7 +1614,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
                    }

                    if (errMsgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT) {
                    if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(errMsgId)) {
                        requestActiveUnlock(
                                ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL,
                                "faceError-" + errMsgId);
@@ -1625,6 +1624,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                @Override
                public void onAuthenticationAcquired(int acquireInfo) {
                    handleFaceAcquired(acquireInfo);

                    if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
                            acquireInfo)) {
                        requestActiveUnlock(
                                ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL,
                                "faceAcquireInfo-" + acquireInfo);
                    }
                }
    };

@@ -1639,6 +1645,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private boolean mFingerprintLockedOut;
    private boolean mFingerprintLockedOutPermanent;
    private boolean mFaceLockedOutPermanent;
    private HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
    private TelephonyManager mTelephonyManager;

    /**
@@ -1889,6 +1896,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        dumpManager.registerDumpable(getClass().getName(), this);
        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
        mActiveUnlockConfig = activeUnlockConfiguration;
        mActiveUnlockConfig.setKeyguardUpdateMonitor(this);

        mHandler = new Handler(mainLooper) {
            @Override
@@ -2329,7 +2337,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }

        if (shouldTriggerActiveUnlock()) {
            if (DEBUG) {
            if (DEBUG_ACTIVE_UNLOCK) {
                Log.d("ActiveUnlock", "initiate active unlock triggerReason=" + reason);
            }
            mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser());
@@ -2359,7 +2367,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }

        if (allowRequest && shouldTriggerActiveUnlock()) {
            if (DEBUG) {
            if (DEBUG_ACTIVE_UNLOCK) {
                Log.d("ActiveUnlock", "reportUserRequestedUnlock"
                        + " origin=" + requestOrigin.name()
                        + " reason=" + reason
@@ -2777,8 +2785,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    }

    private boolean isUnlockWithFingerprintPossible(int userId) {
        return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
                && mFpm.hasEnrolledTemplates(userId);
        mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
                && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
        return mIsUnlockWithFingerprintPossible.get(userId);
    }

    /**
     * Cached value for whether fingerprint is enrolled and possible to use for authentication.
     * Note: checking fingerprint enrollment directly with the AuthController requires an IPC.
     */
    public boolean getCachedIsUnlockWithFingerprintPossible(int userId) {
        return mIsUnlockWithFingerprintPossible.get(userId);
    }

    private boolean isUnlockWithFacePossible(int userId) {
Loading