1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.keyguard 18 19 import android.content.ContentResolver 20 import android.database.ContentObserver 21 import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT 22 import android.net.Uri 23 import android.os.Handler 24 import android.os.PowerManager 25 import android.os.PowerManager.WAKE_REASON_UNFOLD_DEVICE 26 import android.os.UserHandle 27 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL 28 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO 29 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS 30 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT 31 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_LEGACY 32 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED 33 import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE 34 import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS 35 import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD 36 import android.util.Log 37 import com.android.systemui.Dumpable 38 import com.android.systemui.dagger.SysUISingleton 39 import com.android.systemui.dagger.qualifiers.Main 40 import com.android.systemui.dump.DumpManager 41 import com.android.systemui.user.domain.interactor.SelectedUserInteractor 42 import com.android.systemui.util.settings.SecureSettings 43 import java.io.PrintWriter 44 import javax.inject.Inject 45 import dagger.Lazy 46 47 /** 48 * Handles active unlock settings changes. 49 */ 50 @SysUISingleton 51 class ActiveUnlockConfig @Inject constructor( 52 @Main private val handler: Handler, 53 private val secureSettings: SecureSettings, 54 private val contentResolver: ContentResolver, 55 private val selectedUserInteractor: SelectedUserInteractor, 56 private val keyguardUpdateMonitor: Lazy<KeyguardUpdateMonitor>, 57 dumpManager: DumpManager 58 ) : Dumpable { 59 60 companion object { 61 const val TAG = "ActiveUnlockConfig" 62 } 63 64 /** 65 * Indicates the origin for an active unlock request. 66 */ 67 enum class ActiveUnlockRequestOrigin { 68 /** 69 * Trigger ActiveUnlock on wake ups that'd trigger FaceAuth, see [FaceWakeUpTriggersConfig] 70 */ 71 WAKE, 72 73 /** 74 * Trigger ActiveUnlock on unlock intents. This includes the bouncer showing or tapping on 75 * a notification. May also include wakeups: [wakeupsConsideredUnlockIntents]. 76 */ 77 UNLOCK_INTENT, 78 79 /** 80 * Trigger ActiveUnlock on biometric failures. This may include soft errors depending on 81 * the other settings. See: [faceErrorsToTriggerBiometricFailOn], 82 * [faceAcquireInfoToTriggerBiometricFailOn]. 83 */ 84 BIOMETRIC_FAIL, 85 86 /** 87 * Trigger ActiveUnlock when the assistant is triggered. 88 */ 89 ASSISTANT, 90 /** 91 * Trigger ActiveUnlock on legacy unlock intents. This includes tapping on the empty space 92 * of the notification shadse when face auth is enrolled and re-trying face auth on the 93 * primary bouncer. 94 */ 95 UNLOCK_INTENT_LEGACY, 96 } 97 98 /** 99 * Biometric type options. 100 */ 101 enum class BiometricType(val intValue: Int) { 102 NONE(0), 103 ANY_FACE(1), 104 ANY_FINGERPRINT(2), 105 UNDER_DISPLAY_FINGERPRINT(3), 106 } 107 108 private var requestActiveUnlockOnWakeup = false 109 private var requestActiveUnlockOnUnlockIntentLegacy = false 110 private var requestActiveUnlockOnUnlockIntent = false 111 private var requestActiveUnlockOnBioFail = false 112 113 private var faceErrorsToTriggerBiometricFailOn = mutableSetOf<Int>() 114 private var faceAcquireInfoToTriggerBiometricFailOn = mutableSetOf<Int>() 115 private var onUnlockIntentWhenBiometricEnrolled = mutableSetOf<Int>() 116 private var wakeupsConsideredUnlockIntents = mutableSetOf<Int>() 117 private var wakeupsToForceDismissKeyguard = mutableSetOf<Int>() 118 119 private val settingsObserver = object : ContentObserver(handler) { 120 private val wakeUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE) 121 private val unlockIntentLegacyUri = 122 secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_LEGACY) 123 private val unlockIntentUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT) 124 private val bioFailUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL) 125 private val faceErrorsUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS) 126 private val faceAcquireInfoUri = 127 secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO) 128 private val unlockIntentWhenBiometricEnrolledUri = 129 secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED) 130 private val wakeupsConsideredUnlockIntentsUri = 131 secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS) 132 private val wakeupsToForceDismissKeyguardUri = 133 secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD) 134 registernull135 fun register() { 136 registerUri( 137 listOf( 138 wakeUri, 139 unlockIntentUri, 140 bioFailUri, 141 faceErrorsUri, 142 faceAcquireInfoUri, 143 unlockIntentWhenBiometricEnrolledUri, 144 wakeupsConsideredUnlockIntentsUri, 145 wakeupsToForceDismissKeyguardUri, 146 ) 147 ) 148 149 onChange(true, ArrayList(), 0, selectedUserInteractor.getSelectedUserId()) 150 } 151 registerUrinull152 private fun registerUri(uris: Collection<Uri>) { 153 for (uri in uris) { 154 contentResolver.registerContentObserver( 155 uri, 156 false, 157 this, 158 UserHandle.USER_ALL) 159 } 160 } 161 onChangenull162 override fun onChange( 163 selfChange: Boolean, 164 uris: Collection<Uri>, 165 flags: Int, 166 userId: Int 167 ) { 168 if (selectedUserInteractor.getSelectedUserId() != userId) { 169 return 170 } 171 172 if (selfChange || uris.contains(wakeUri)) { 173 requestActiveUnlockOnWakeup = secureSettings.getIntForUser( 174 ACTIVE_UNLOCK_ON_WAKE, 0, selectedUserInteractor.getSelectedUserId()) == 1 175 } 176 177 if (selfChange || uris.contains(unlockIntentLegacyUri)) { 178 requestActiveUnlockOnUnlockIntentLegacy = 179 secureSettings.getIntForUser( 180 ACTIVE_UNLOCK_ON_UNLOCK_INTENT_LEGACY, 181 0, 182 selectedUserInteractor.getSelectedUserId() 183 ) == 1 184 } 185 186 if (selfChange || uris.contains(unlockIntentUri)) { 187 requestActiveUnlockOnUnlockIntent = secureSettings.getIntForUser( 188 ACTIVE_UNLOCK_ON_UNLOCK_INTENT, 0, 189 selectedUserInteractor.getSelectedUserId()) == 1 190 } 191 192 if (selfChange || uris.contains(bioFailUri)) { 193 requestActiveUnlockOnBioFail = secureSettings.getIntForUser( 194 ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 0, 195 selectedUserInteractor.getSelectedUserId()) == 1 196 } 197 198 if (selfChange || uris.contains(faceErrorsUri)) { 199 processStringArray( 200 secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ERRORS, 201 selectedUserInteractor.getSelectedUserId()), 202 faceErrorsToTriggerBiometricFailOn, 203 setOf(FACE_ERROR_TIMEOUT)) 204 } 205 206 if (selfChange || uris.contains(faceAcquireInfoUri)) { 207 processStringArray( 208 secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO, 209 selectedUserInteractor.getSelectedUserId()), 210 faceAcquireInfoToTriggerBiometricFailOn, 211 emptySet()) 212 } 213 214 if (selfChange || uris.contains(unlockIntentWhenBiometricEnrolledUri)) { 215 processStringArray( 216 secureSettings.getStringForUser( 217 ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, 218 selectedUserInteractor.getSelectedUserId()), 219 onUnlockIntentWhenBiometricEnrolled, 220 setOf(BiometricType.NONE.intValue)) 221 } 222 223 if (selfChange || uris.contains(wakeupsConsideredUnlockIntentsUri)) { 224 processStringArray( 225 secureSettings.getStringForUser( 226 ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, 227 selectedUserInteractor.getSelectedUserId()), 228 wakeupsConsideredUnlockIntents, 229 setOf(WAKE_REASON_UNFOLD_DEVICE)) 230 } 231 232 if (selfChange || uris.contains(wakeupsToForceDismissKeyguardUri)) { 233 processStringArray( 234 secureSettings.getStringForUser( 235 ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD, 236 selectedUserInteractor.getSelectedUserId()), 237 wakeupsToForceDismissKeyguard, 238 setOf(WAKE_REASON_UNFOLD_DEVICE)) 239 } 240 } 241 242 /** 243 * Convert a pipe-separated set of integers into a set of ints. 244 * @param stringSetting expected input are integers delineated by a pipe. For example, 245 * it may look something like this: "1|5|3". 246 * @param out updates the "out" Set will the integers between the pipes. 247 * @param default If stringSetting is null, "out" will be populated with values in "default" 248 */ processStringArraynull249 private fun processStringArray( 250 stringSetting: String?, 251 out: MutableSet<Int>, 252 default: Set<Int> 253 ) { 254 out.clear() 255 stringSetting?.let { 256 for (code: String in stringSetting.split("|")) { 257 if (code.isNotEmpty()) { 258 try { 259 out.add(code.toInt()) 260 } catch (e: NumberFormatException) { 261 Log.e(TAG, "Passed an invalid setting=$code") 262 } 263 } 264 } 265 } ?: out.addAll(default) 266 } 267 } 268 269 init { 270 settingsObserver.register() 271 dumpManager.registerDumpable(this) 272 } 273 274 /** 275 * If any active unlock triggers are enabled. 276 */ isActiveUnlockEnablednull277 fun isActiveUnlockEnabled(): Boolean { 278 return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent || 279 requestActiveUnlockOnBioFail || requestActiveUnlockOnUnlockIntentLegacy 280 } 281 282 /** 283 * Whether the face error code from {@link BiometricFaceConstants} should trigger 284 * active unlock on biometric failure. 285 */ shouldRequestActiveUnlockOnFaceErrornull286 fun shouldRequestActiveUnlockOnFaceError(errorCode: Int): Boolean { 287 return faceErrorsToTriggerBiometricFailOn.contains(errorCode) 288 } 289 290 /** 291 * Whether the face acquireInfo from {@link BiometricFaceConstants} should trigger 292 * active unlock on biometric failure. 293 */ shouldRequestActiveUnlockOnFaceAcquireInfonull294 fun shouldRequestActiveUnlockOnFaceAcquireInfo(acquiredInfo: Int): Boolean { 295 return faceAcquireInfoToTriggerBiometricFailOn.contains(acquiredInfo) 296 } 297 298 /** 299 * Whether the PowerManager wake reason is considered an unlock intent and should use origin 300 * [ActiveUnlockRequestOrigin.UNLOCK_INTENT] instead of [ActiveUnlockRequestOrigin.WAKE]. 301 */ isWakeupConsideredUnlockIntentnull302 fun isWakeupConsideredUnlockIntent(pmWakeReason: Int): Boolean { 303 return wakeupsConsideredUnlockIntents.contains(pmWakeReason) 304 } 305 306 /** 307 * Whether the PowerManager wake reason should force dismiss the keyguard if active 308 * unlock is successful. 309 */ shouldWakeupForceDismissKeyguardnull310 fun shouldWakeupForceDismissKeyguard(pmWakeReason: Int): Boolean { 311 return wakeupsToForceDismissKeyguard.contains(pmWakeReason) 312 } 313 314 /** 315 * Whether to trigger active unlock based on where the request is coming from and 316 * the current settings. 317 */ shouldAllowActiveUnlockFromOriginnull318 fun shouldAllowActiveUnlockFromOrigin(requestOrigin: ActiveUnlockRequestOrigin): Boolean { 319 return when (requestOrigin) { 320 ActiveUnlockRequestOrigin.WAKE -> requestActiveUnlockOnWakeup 321 ActiveUnlockRequestOrigin.UNLOCK_INTENT_LEGACY -> 322 requestActiveUnlockOnUnlockIntentLegacy 323 ActiveUnlockRequestOrigin.UNLOCK_INTENT -> 324 requestActiveUnlockOnUnlockIntent || 325 requestActiveUnlockOnUnlockIntentLegacy || 326 requestActiveUnlockOnWakeup || 327 (shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()) 328 ActiveUnlockRequestOrigin.BIOMETRIC_FAIL -> 329 requestActiveUnlockOnBioFail || 330 requestActiveUnlockOnUnlockIntentLegacy || 331 requestActiveUnlockOnUnlockIntent || 332 requestActiveUnlockOnWakeup 333 ActiveUnlockRequestOrigin.ASSISTANT -> isActiveUnlockEnabled() 334 } 335 } 336 shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollmentnull337 private fun shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment(): Boolean { 338 if (!requestActiveUnlockOnBioFail) { 339 return false 340 } 341 342 keyguardUpdateMonitor.get().let { 343 val anyFaceEnrolled = it.isFaceEnabledAndEnrolled 344 val anyFingerprintEnrolled = it.isUnlockWithFingerprintPossible( 345 selectedUserInteractor.getSelectedUserId()) 346 val udfpsEnrolled = it.isUdfpsEnrolled 347 348 if (!anyFaceEnrolled && !anyFingerprintEnrolled) { 349 return onUnlockIntentWhenBiometricEnrolled.contains(BiometricType.NONE.intValue) 350 } 351 352 if (!anyFaceEnrolled && anyFingerprintEnrolled) { 353 return onUnlockIntentWhenBiometricEnrolled.contains( 354 BiometricType.ANY_FINGERPRINT.intValue) || 355 (udfpsEnrolled && onUnlockIntentWhenBiometricEnrolled.contains( 356 BiometricType.UNDER_DISPLAY_FINGERPRINT.intValue)) 357 } 358 359 if (!anyFingerprintEnrolled && anyFaceEnrolled) { 360 return onUnlockIntentWhenBiometricEnrolled.contains(BiometricType.ANY_FACE.intValue) 361 } 362 } 363 364 return false 365 } 366 dumpnull367 override fun dump(pw: PrintWriter, args: Array<out String>) { 368 pw.println("Settings:") 369 pw.println(" requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup") 370 pw.println( 371 " requestActiveUnlockOnUnlockIntentLegacy=$requestActiveUnlockOnUnlockIntentLegacy" 372 ) 373 pw.println(" requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent") 374 pw.println(" requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail") 375 376 val onUnlockIntentWhenBiometricEnrolledString = 377 onUnlockIntentWhenBiometricEnrolled.map { 378 for (biometricType in BiometricType.values()) { 379 if (biometricType.intValue == it) { 380 return@map biometricType.name 381 } 382 } 383 return@map "UNKNOWN" 384 } 385 pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" + 386 "$onUnlockIntentWhenBiometricEnrolledString") 387 pw.println(" requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn") 388 pw.println(" requestActiveUnlockOnFaceAcquireInfo=" + 389 "$faceAcquireInfoToTriggerBiometricFailOn") 390 pw.println(" activeUnlockWakeupsConsideredUnlockIntents=${ 391 wakeupsConsideredUnlockIntents.map { PowerManager.wakeReasonToString(it) } 392 }") 393 pw.println(" activeUnlockFromWakeupsToAlwaysDismissKeyguard=${ 394 wakeupsToForceDismissKeyguard.map { PowerManager.wakeReasonToString(it) } 395 }") 396 397 pw.println("Current state:") 398 keyguardUpdateMonitor.get().let { 399 pw.println(" shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" + 400 "${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}") 401 pw.println(" isFaceEnabledAndEnrolled=${it.isFaceEnabledAndEnrolled}") 402 pw.println(" fpUnlockPossible=${ 403 it.isUnlockWithFingerprintPossible(selectedUserInteractor.getSelectedUserId())}") 404 pw.println(" udfpsEnrolled=${it.isUdfpsEnrolled}") 405 } 406 } 407 }