Loading core/java/android/provider/Settings.java +34 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +3 −0 Original line number Diff line number Diff line Loading @@ -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, Loading packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt +172 −25 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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. */ Loading @@ -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( Loading @@ -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) } } Loading @@ -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. Loading @@ -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 || Loading @@ -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 packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +23 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); } } }; Loading @@ -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; /** Loading Loading @@ -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 Loading Loading @@ -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()); Loading Loading @@ -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 Loading Loading @@ -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 Loading
core/java/android/provider/Settings.java +34 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading
packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +3 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading
packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt +172 −25 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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. */ Loading @@ -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( Loading @@ -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) } } Loading @@ -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. Loading @@ -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 || Loading @@ -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
packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +23 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); } } }; Loading @@ -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; /** Loading Loading @@ -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 Loading Loading @@ -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()); Loading Loading @@ -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 Loading Loading @@ -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