1 /* 2 * Copyright (C) 2007 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 android.app; 18 19 import android.Manifest; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresFeature; 25 import android.annotation.RequiresPermission; 26 import android.annotation.SystemApi; 27 import android.annotation.SystemService; 28 import android.annotation.TestApi; 29 import android.app.admin.DevicePolicyManager; 30 import android.app.admin.DevicePolicyManager.PasswordComplexity; 31 import android.app.admin.PasswordMetrics; 32 import android.app.trust.ITrustManager; 33 import android.compat.annotation.UnsupportedAppUsage; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.pm.PackageManager; 38 import android.content.pm.ResolveInfo; 39 import android.os.Binder; 40 import android.os.Build; 41 import android.os.IBinder; 42 import android.os.RemoteException; 43 import android.os.ServiceManager; 44 import android.os.ServiceManager.ServiceNotFoundException; 45 import android.os.UserHandle; 46 import android.provider.Settings; 47 import android.service.persistentdata.IPersistentDataBlockService; 48 import android.util.ArrayMap; 49 import android.util.Log; 50 import android.view.IOnKeyguardExitResult; 51 import android.view.IWindowManager; 52 import android.view.WindowManager.LayoutParams; 53 import android.view.WindowManagerGlobal; 54 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.internal.policy.IKeyguardDismissCallback; 57 import com.android.internal.policy.IKeyguardLockedStateListener; 58 import com.android.internal.util.Preconditions; 59 import com.android.internal.widget.IWeakEscrowTokenActivatedListener; 60 import com.android.internal.widget.IWeakEscrowTokenRemovedListener; 61 import com.android.internal.widget.LockPatternUtils; 62 import com.android.internal.widget.LockPatternView; 63 import com.android.internal.widget.LockscreenCredential; 64 import com.android.internal.widget.VerifyCredentialResponse; 65 66 import java.nio.charset.Charset; 67 import java.util.Arrays; 68 import java.util.List; 69 import java.util.Objects; 70 import java.util.concurrent.Executor; 71 72 /** 73 * Class that can be used to lock and unlock the keyguard. The 74 * actual class to control the keyguard locking is 75 * {@link android.app.KeyguardManager.KeyguardLock}. 76 */ 77 @SystemService(Context.KEYGUARD_SERVICE) 78 public class KeyguardManager { 79 80 private static final String TAG = "KeyguardManager"; 81 82 private final Context mContext; 83 private final LockPatternUtils mLockPatternUtils; 84 private final IWindowManager mWM; 85 private final IActivityManager mAm; 86 private final ITrustManager mTrustManager; 87 private final INotificationManager mNotificationManager; 88 private final ArrayMap<WeakEscrowTokenRemovedListener, IWeakEscrowTokenRemovedListener> 89 mListeners = new ArrayMap<>(); 90 91 /** 92 * Intent used to prompt user for device credentials. 93 * @hide 94 */ 95 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL = 96 "android.app.action.CONFIRM_DEVICE_CREDENTIAL"; 97 98 /** 99 * Intent used to prompt user for device credentials. 100 * @hide 101 */ 102 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER = 103 "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER"; 104 105 /** 106 * Intent used to prompt user for factory reset credentials. 107 * @hide 108 */ 109 public static final String ACTION_CONFIRM_FRP_CREDENTIAL = 110 "android.app.action.CONFIRM_FRP_CREDENTIAL"; 111 112 /** 113 * Intent used to prompt user to to validate the credentials of a remote device. 114 * @hide 115 */ 116 public static final String ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL = 117 "android.app.action.CONFIRM_REMOTE_DEVICE_CREDENTIAL"; 118 119 /** 120 * Intent used to prompt user for device credential for entering repair 121 * mode. If the credential is verified successfully, then the information 122 * needed to verify the credential again will be written to a location that 123 * is available to repair mode. This makes it possible for repair mode to 124 * require that the same credential be provided to exit repair mode. 125 * @hide 126 */ 127 public static final String ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL = 128 "android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL"; 129 130 /** 131 * Intent used to prompt user for device credential that is written by 132 * {@link #ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL} for exiting 133 * repair mode. 134 * @hide 135 */ 136 public static final String ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL = 137 "android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL"; 138 139 /** 140 * A CharSequence dialog title to show to the user when used with a 141 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 142 * @hide 143 */ 144 public static final String EXTRA_TITLE = "android.app.extra.TITLE"; 145 146 /** 147 * A CharSequence description to show to the user when used with 148 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 149 * @hide 150 */ 151 public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION"; 152 153 /** 154 * A CharSequence description to show to the user on the alternate button when used with 155 * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}. 156 * @hide 157 */ 158 public static final String EXTRA_ALTERNATE_BUTTON_LABEL = 159 "android.app.extra.ALTERNATE_BUTTON_LABEL"; 160 161 /** 162 * A CharSequence label for the checkbox when used with 163 * {@link #ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL} 164 * @hide 165 */ 166 public static final String EXTRA_CHECKBOX_LABEL = "android.app.extra.CHECKBOX_LABEL"; 167 168 /** 169 * A {@link RemoteLockscreenValidationSession} extra to be sent along with 170 * {@link #ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL} containing the data needed to prompt for 171 * a remote device's lock screen. 172 * @hide 173 */ 174 public static final String EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION = 175 "android.app.extra.REMOTE_LOCKSCREEN_VALIDATION_SESSION"; 176 177 /** 178 * A boolean indicating that credential confirmation activity should be a task overlay. 179 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER}. 180 * @hide 181 */ 182 public static final String EXTRA_FORCE_TASK_OVERLAY = 183 "android.app.KeyguardManager.FORCE_TASK_OVERLAY"; 184 185 /** 186 * Result code returned by the activity started by 187 * {@link #createConfirmFactoryResetCredentialIntent} or 188 * {@link #createConfirmDeviceCredentialForRemoteValidationIntent} 189 * indicating that the user clicked the alternate button. 190 * 191 * @hide 192 */ 193 public static final int RESULT_ALTERNATE = 1; 194 195 /** 196 * 197 * If this is set, check device policy for allowed biometrics when the user is authenticating. 198 * This should only be used in the context of managed profiles. 199 * 200 * @hide 201 */ 202 public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm"; 203 204 /** 205 * 206 * Password lock type, see {@link #setLock} 207 * 208 * @hide 209 */ 210 @SystemApi 211 public static final int PASSWORD = 0; 212 213 /** 214 * 215 * Pin lock type, see {@link #setLock} 216 * 217 * @hide 218 */ 219 @SystemApi 220 public static final int PIN = 1; 221 222 /** 223 * 224 * Pattern lock type, see {@link #setLock} 225 * 226 * @hide 227 */ 228 @SystemApi 229 public static final int PATTERN = 2; 230 231 /** 232 * Available lock types 233 */ 234 @IntDef({ 235 PASSWORD, 236 PIN, 237 PATTERN 238 }) 239 @interface LockTypes {} 240 241 private final IKeyguardLockedStateListener mIKeyguardLockedStateListener = 242 new IKeyguardLockedStateListener.Stub() { 243 @Override 244 public void onKeyguardLockedStateChanged(boolean isKeyguardLocked) { 245 mKeyguardLockedStateListeners.forEach((listener, executor) -> { 246 executor.execute( 247 () -> listener.onKeyguardLockedStateChanged(isKeyguardLocked)); 248 }); 249 } 250 }; 251 private final ArrayMap<KeyguardLockedStateListener, Executor> 252 mKeyguardLockedStateListeners = new ArrayMap<>(); 253 254 /** 255 * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics 256 * if enrolled) for the current user of the device. The caller is expected to launch this 257 * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 258 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 259 * 260 * @return the intent for launching the activity or null if no password is required. 261 * @deprecated see BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean) 262 */ 263 @Deprecated 264 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description)265 public Intent createConfirmDeviceCredentialIntent(CharSequence title, 266 CharSequence description) { 267 if (!isDeviceSecure()) return null; 268 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL); 269 intent.putExtra(EXTRA_TITLE, title); 270 intent.putExtra(EXTRA_DESCRIPTION, description); 271 272 // explicitly set the package for security 273 intent.setPackage(getSettingsPackageForIntent(intent)); 274 return intent; 275 } 276 277 /** 278 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 279 * for the given user. The caller is expected to launch this activity using 280 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 281 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 282 * 283 * @return the intent for launching the activity or null if no password is required. 284 * 285 * @hide 286 */ createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId)287 public Intent createConfirmDeviceCredentialIntent( 288 CharSequence title, CharSequence description, int userId) { 289 if (!isDeviceSecure(userId)) return null; 290 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); 291 intent.putExtra(EXTRA_TITLE, title); 292 intent.putExtra(EXTRA_DESCRIPTION, description); 293 intent.putExtra(Intent.EXTRA_USER_ID, userId); 294 295 // explicitly set the package for security 296 intent.setPackage(getSettingsPackageForIntent(intent)); 297 298 return intent; 299 } 300 301 /** 302 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 303 * for the given user. The caller is expected to launch this activity using 304 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 305 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 306 * 307 * @param disallowBiometricsIfPolicyExists If true check if the Device Policy Manager has 308 * disabled biometrics on the device. If biometrics are disabled, fall back to PIN/pattern/pass. 309 * 310 * @return the intent for launching the activity or null if no password is required. 311 * 312 * @hide 313 */ createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId, boolean disallowBiometricsIfPolicyExists)314 public Intent createConfirmDeviceCredentialIntent( 315 CharSequence title, CharSequence description, int userId, 316 boolean disallowBiometricsIfPolicyExists) { 317 Intent intent = this.createConfirmDeviceCredentialIntent(title, description, userId); 318 if (intent != null) { 319 intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, 320 disallowBiometricsIfPolicyExists); 321 } 322 return intent; 323 } 324 325 /** 326 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 327 * for the previous owner of the device. The caller is expected to launch this activity using 328 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 329 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 330 * 331 * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon 332 * clicking this button, the activity returns 333 * {@link #RESULT_ALTERNATE} 334 * 335 * @return the intent for launching the activity or null if the previous owner of the device 336 * did not set a credential. 337 * @throws UnsupportedOperationException if the device does not support factory reset 338 * credentials 339 * @throws IllegalStateException if the device has already been provisioned 340 * @hide 341 */ 342 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 343 @SystemApi createConfirmFactoryResetCredentialIntent( CharSequence title, CharSequence description, CharSequence alternateButtonLabel)344 public Intent createConfirmFactoryResetCredentialIntent( 345 CharSequence title, CharSequence description, CharSequence alternateButtonLabel) { 346 if (!LockPatternUtils.frpCredentialEnabled(mContext)) { 347 Log.w(TAG, "Factory reset credentials not supported."); 348 throw new UnsupportedOperationException("not supported on this device"); 349 } 350 351 // Cannot verify credential if the device is provisioned 352 if (Settings.Global.getInt(mContext.getContentResolver(), 353 Settings.Global.DEVICE_PROVISIONED, 0) != 0) { 354 Log.e(TAG, "Factory reset credential cannot be verified after provisioning."); 355 throw new IllegalStateException("must not be provisioned yet"); 356 } 357 358 // Make sure we have a credential 359 try { 360 IPersistentDataBlockService pdb = IPersistentDataBlockService.Stub.asInterface( 361 ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE)); 362 if (pdb == null) { 363 Log.e(TAG, "No persistent data block service"); 364 throw new UnsupportedOperationException("not supported on this device"); 365 } 366 // The following will throw an UnsupportedOperationException if the device does not 367 // support factory reset credentials (or something went wrong retrieving it). 368 if (!pdb.hasFrpCredentialHandle()) { 369 Log.i(TAG, "The persistent data block does not have a factory reset credential."); 370 return null; 371 } 372 } catch (RemoteException e) { 373 throw e.rethrowFromSystemServer(); 374 } 375 376 Intent intent = new Intent(ACTION_CONFIRM_FRP_CREDENTIAL); 377 intent.putExtra(EXTRA_TITLE, title); 378 intent.putExtra(EXTRA_DESCRIPTION, description); 379 intent.putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel); 380 381 // explicitly set the package for security 382 intent.setPackage(getSettingsPackageForIntent(intent)); 383 384 return intent; 385 } 386 387 /** 388 * Get an Intent to launch an activity to prompt the user to confirm the 389 * credentials (pin, pattern or password) of a remote device. 390 * @param session contains information necessary to start remote device credential validation. 391 * @param remoteLockscreenValidationServiceComponent 392 * the {@link ComponentName} of the implementation of 393 * {@link android.service.remotelockscreenvalidation.RemoteLockscreenValidationService} 394 * @param checkboxLabel if not empty, a checkbox is provided with the given label. When checked, 395 * the validated remote device credential will be set as the device lock of 396 * the current device. 397 * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon 398 * clicking this button, the activity returns 399 * {@link #RESULT_ALTERNATE}. 400 * @hide 401 */ 402 @SystemApi 403 @RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN) 404 @NonNull createConfirmDeviceCredentialForRemoteValidationIntent( @onNull RemoteLockscreenValidationSession session, @NonNull ComponentName remoteLockscreenValidationServiceComponent, @Nullable CharSequence title, @Nullable CharSequence description, @Nullable CharSequence checkboxLabel, @Nullable CharSequence alternateButtonLabel)405 public Intent createConfirmDeviceCredentialForRemoteValidationIntent( 406 @NonNull RemoteLockscreenValidationSession session, 407 @NonNull ComponentName remoteLockscreenValidationServiceComponent, 408 @Nullable CharSequence title, 409 @Nullable CharSequence description, 410 @Nullable CharSequence checkboxLabel, 411 @Nullable CharSequence alternateButtonLabel) { 412 Intent intent = new Intent(ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL) 413 .putExtra(EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION, session) 414 .putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent) 415 .putExtra(EXTRA_TITLE, title) 416 .putExtra(EXTRA_DESCRIPTION, description) 417 .putExtra(EXTRA_CHECKBOX_LABEL, checkboxLabel) 418 .putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel); 419 420 // explicitly set the package for security 421 intent.setPackage(getSettingsPackageForIntent(intent)); 422 423 return intent; 424 } 425 426 /** 427 * Controls whether notifications can be shown atop a securely locked screen in their full 428 * private form (same as when the device is unlocked). 429 * 430 * <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration. 431 * The result is that private notifications are only shown if all sources allow it. 432 * 433 * @param allow secure notifications can be shown if {@code true}, 434 * secure notifications cannot be shown if {@code false} 435 * @hide 436 */ 437 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 438 @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) 439 @SystemApi setPrivateNotificationsAllowed(boolean allow)440 public void setPrivateNotificationsAllowed(boolean allow) { 441 try { 442 mNotificationManager.setPrivateNotificationsAllowed(allow); 443 } catch (RemoteException e) { 444 throw e.rethrowFromSystemServer(); 445 } 446 } 447 448 /** 449 * Returns whether notifications can be shown atop a securely locked screen in their full 450 * private form (same as when the device is unlocked). 451 * 452 * @return {@code true} if secure notifications can be shown, {@code false} otherwise. 453 * By default, private notifications are allowed. 454 * @hide 455 */ 456 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 457 @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) 458 @SystemApi getPrivateNotificationsAllowed()459 public boolean getPrivateNotificationsAllowed() { 460 try { 461 return mNotificationManager.getPrivateNotificationsAllowed(); 462 } catch (RemoteException e) { 463 throw e.rethrowFromSystemServer(); 464 } 465 } 466 getSettingsPackageForIntent(Intent intent)467 private String getSettingsPackageForIntent(Intent intent) { 468 List<ResolveInfo> resolveInfos = mContext.getPackageManager() 469 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY); 470 for (int i = 0; i < resolveInfos.size(); i++) { 471 return resolveInfos.get(i).activityInfo.packageName; 472 } 473 474 return "com.android.settings"; 475 } 476 477 /** 478 * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows 479 * you to disable / reenable the keyguard. 480 * 481 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 482 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 483 * instead; this allows you to seamlessly hide the keyguard as your application 484 * moves in and out of the foreground and does not require that any special 485 * permissions be requested. 486 */ 487 @Deprecated 488 public class KeyguardLock { 489 private final IBinder mToken = new Binder(); 490 private final String mTag; 491 KeyguardLock(String tag)492 KeyguardLock(String tag) { 493 mTag = tag; 494 } 495 496 /** 497 * Disable the keyguard from showing. If the keyguard is currently 498 * showing, hide it. The keyguard will be prevented from showing again 499 * until {@link #reenableKeyguard()} is called. 500 * 501 * A good place to call this is from {@link android.app.Activity#onResume()} 502 * 503 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 504 * is enabled that requires a password. 505 * 506 * @see #reenableKeyguard() 507 */ 508 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) disableKeyguard()509 public void disableKeyguard() { 510 try { 511 mWM.disableKeyguard(mToken, mTag, mContext.getUserId()); 512 } catch (RemoteException ex) { 513 } 514 } 515 516 /** 517 * Reenable the keyguard. The keyguard will reappear if the previous 518 * call to {@link #disableKeyguard()} caused it to be hidden. 519 * 520 * A good place to call this is from {@link android.app.Activity#onPause()} 521 * 522 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 523 * is enabled that requires a password. 524 * 525 * @see #disableKeyguard() 526 */ 527 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) reenableKeyguard()528 public void reenableKeyguard() { 529 try { 530 mWM.reenableKeyguard(mToken, mContext.getUserId()); 531 } catch (RemoteException ex) { 532 } 533 } 534 } 535 536 /** 537 * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify 538 * caller of result. 539 * 540 * @deprecated Use {@link KeyguardDismissCallback} 541 */ 542 @Deprecated 543 public interface OnKeyguardExitResult { 544 545 /** 546 * @param success True if the user was able to authenticate, false if 547 * not. 548 */ onKeyguardExitResult(boolean success)549 void onKeyguardExitResult(boolean success); 550 } 551 552 /** 553 * Callback passed to 554 * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardDismissCallback)} 555 * to notify caller of result. 556 */ 557 public static abstract class KeyguardDismissCallback { 558 559 /** 560 * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not 561 * available, not showing or when the activity requesting the Keyguard dismissal isn't 562 * showing or isn't showing behind Keyguard. 563 */ onDismissError()564 public void onDismissError() { } 565 566 /** 567 * Called when dismissing Keyguard has succeeded and the device is now unlocked. 568 */ onDismissSucceeded()569 public void onDismissSucceeded() { } 570 571 /** 572 * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the 573 * operation or the bouncer was hidden for some other reason. 574 */ onDismissCancelled()575 public void onDismissCancelled() { } 576 } 577 578 /** 579 * Callback passed to 580 * {@link KeyguardManager#addWeakEscrowToken} 581 * to notify caller of state change. 582 * @hide 583 */ 584 @SystemApi 585 public interface WeakEscrowTokenActivatedListener { 586 /** 587 * The method to be called when the token is activated. 588 * @param handle 64 bit handle corresponding to the escrow token 589 * @param user user for whom the weak escrow token has been added 590 */ onWeakEscrowTokenActivated(long handle, @NonNull UserHandle user)591 void onWeakEscrowTokenActivated(long handle, @NonNull UserHandle user); 592 } 593 594 /** 595 * Listener passed to 596 * {@link KeyguardManager#registerWeakEscrowTokenRemovedListener} and 597 * {@link KeyguardManager#unregisterWeakEscrowTokenRemovedListener} 598 * to notify caller of an weak escrow token has been removed. 599 * @hide 600 */ 601 @SystemApi 602 public interface WeakEscrowTokenRemovedListener { 603 /** 604 * The method to be called when the token is removed. 605 * @param handle 64 bit handle corresponding to the escrow token 606 * @param user user for whom the escrow token has been added 607 */ onWeakEscrowTokenRemoved(long handle, @NonNull UserHandle user)608 void onWeakEscrowTokenRemoved(long handle, @NonNull UserHandle user); 609 } 610 KeyguardManager(Context context)611 KeyguardManager(Context context) throws ServiceNotFoundException { 612 mContext = context; 613 mLockPatternUtils = new LockPatternUtils(context); 614 mWM = WindowManagerGlobal.getWindowManagerService(); 615 mAm = ActivityManager.getService(); 616 mTrustManager = ITrustManager.Stub.asInterface( 617 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE)); 618 mNotificationManager = INotificationManager.Stub.asInterface( 619 ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE)); 620 } 621 622 /** 623 * Enables you to lock or unlock the keyguard. Get an instance of this class by 624 * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 625 * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}. 626 * @param tag A tag that informally identifies who you are (for debugging who 627 * is disabling the keyguard). 628 * 629 * @return A {@link KeyguardLock} handle to use to disable and reenable the 630 * keyguard. 631 * 632 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 633 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 634 * instead; this allows you to seamlessly hide the keyguard as your application 635 * moves in and out of the foreground and does not require that any special 636 * permissions be requested. 637 */ 638 @Deprecated newKeyguardLock(String tag)639 public KeyguardLock newKeyguardLock(String tag) { 640 return new KeyguardLock(tag); 641 } 642 643 /** 644 * Return whether the keyguard is currently locked. 645 * 646 * @return {@code true} if the keyguard is locked. 647 */ isKeyguardLocked()648 public boolean isKeyguardLocked() { 649 try { 650 return mWM.isKeyguardLocked(); 651 } catch (RemoteException ex) { 652 return false; 653 } 654 } 655 656 /** 657 * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card 658 * is currently locked. 659 * 660 * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states. 661 * 662 * @return {@code true} if a PIN, pattern or password is set or a SIM card is locked. 663 */ isKeyguardSecure()664 public boolean isKeyguardSecure() { 665 try { 666 return mWM.isKeyguardSecure(mContext.getUserId()); 667 } catch (RemoteException ex) { 668 return false; 669 } 670 } 671 672 /** 673 * If keyguard screen is showing or in restricted key input mode (i.e. in 674 * keyguard password emergency screen). When in such mode, certain keys, 675 * such as the Home key and the right soft keys, don't work. 676 * 677 * @return {@code true} if in keyguard restricted input mode. 678 * @deprecated Use {@link #isKeyguardLocked()} instead. 679 */ inKeyguardRestrictedInputMode()680 public boolean inKeyguardRestrictedInputMode() { 681 return isKeyguardLocked(); 682 } 683 684 /** 685 * Returns whether the device is currently locked and requires a PIN, pattern or 686 * password to unlock. 687 * 688 * @return {@code true} if unlocking the device currently requires a PIN, pattern or 689 * password. 690 */ isDeviceLocked()691 public boolean isDeviceLocked() { 692 return isDeviceLocked(mContext.getUserId()); 693 } 694 695 /** 696 * Per-user version of {@link #isDeviceLocked()}. 697 * 698 * @hide 699 */ 700 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) isDeviceLocked(int userId)701 public boolean isDeviceLocked(int userId) { 702 try { 703 return mTrustManager.isDeviceLocked(userId, mContext.getAssociatedDisplayId()); 704 } catch (RemoteException e) { 705 return false; 706 } 707 } 708 709 /** 710 * Returns whether the device is secured with a PIN, pattern or 711 * password. 712 * 713 * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure. 714 * 715 * @return {@code true} if a PIN, pattern or password was set. 716 */ isDeviceSecure()717 public boolean isDeviceSecure() { 718 return isDeviceSecure(mContext.getUserId()); 719 } 720 721 /** 722 * Per-user version of {@link #isDeviceSecure()}. 723 * 724 * @hide 725 */ 726 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isDeviceSecure(int userId)727 public boolean isDeviceSecure(int userId) { 728 try { 729 return mTrustManager.isDeviceSecure(userId, mContext.getAssociatedDisplayId()); 730 } catch (RemoteException e) { 731 return false; 732 } 733 } 734 735 /** 736 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 737 * be dismissed. 738 * <p> 739 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 740 * method will immediately dismiss the Keyguard without any user interaction. 741 * <p> 742 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 743 * UI so the user can enter their credentials. 744 * <p> 745 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 746 * the screen will turn on when the keyguard is dismissed. 747 * 748 * @param activity The activity requesting the dismissal. The activity must be either visible 749 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 750 * which it would be visible if Keyguard would not be hiding it. If that's not 751 * the case, the request will fail immediately and 752 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 753 * @param callback The callback to be called if the request to dismiss Keyguard was successful 754 * or {@code null} if the caller isn't interested in knowing the result. The 755 * callback will not be invoked if the activity was destroyed before the 756 * callback was received. 757 */ requestDismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback)758 public void requestDismissKeyguard(@NonNull Activity activity, 759 @Nullable KeyguardDismissCallback callback) { 760 requestDismissKeyguard(activity, null /* message */, callback); 761 } 762 763 /** 764 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 765 * be dismissed. 766 * <p> 767 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 768 * method will immediately dismiss the Keyguard without any user interaction. 769 * <p> 770 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 771 * UI so the user can enter their credentials. 772 * <p> 773 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 774 * the screen will turn on when the keyguard is dismissed. 775 * 776 * @param activity The activity requesting the dismissal. The activity must be either visible 777 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 778 * which it would be visible if Keyguard would not be hiding it. If that's not 779 * the case, the request will fail immediately and 780 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 781 * @param message A message that will be shown in the keyguard explaining why the user 782 * would want to dismiss it. 783 * @param callback The callback to be called if the request to dismiss Keyguard was successful 784 * or {@code null} if the caller isn't interested in knowing the result. The 785 * callback will not be invoked if the activity was destroyed before the 786 * callback was received. 787 * @hide 788 */ 789 @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE) 790 @SystemApi requestDismissKeyguard(@onNull Activity activity, @Nullable CharSequence message, @Nullable KeyguardDismissCallback callback)791 public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message, 792 @Nullable KeyguardDismissCallback callback) { 793 ActivityClient.getInstance().dismissKeyguard( 794 activity.getActivityToken(), new IKeyguardDismissCallback.Stub() { 795 @Override 796 public void onDismissError() throws RemoteException { 797 if (callback != null && !activity.isDestroyed()) { 798 activity.mHandler.post(callback::onDismissError); 799 } 800 } 801 802 @Override 803 public void onDismissSucceeded() throws RemoteException { 804 if (callback != null && !activity.isDestroyed()) { 805 activity.mHandler.post(callback::onDismissSucceeded); 806 } 807 } 808 809 @Override 810 public void onDismissCancelled() throws RemoteException { 811 if (callback != null && !activity.isDestroyed()) { 812 activity.mHandler.post(callback::onDismissCancelled); 813 } 814 } 815 }, message); 816 } 817 818 /** 819 * Exit the keyguard securely. The use case for this api is that, after 820 * disabling the keyguard, your app, which was granted permission to 821 * disable the keyguard and show a limited amount of information deemed 822 * safe without the user getting past the keyguard, needs to navigate to 823 * something that is not safe to view without getting past the keyguard. 824 * 825 * This will, if the keyguard is secure, bring up the unlock screen of 826 * the keyguard. 827 * 828 * @param callback Lets you know whether the operation was successful and 829 * it is safe to launch anything that would normally be considered safe 830 * once the user has gotten past the keyguard. 831 832 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 833 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 834 * instead; this allows you to seamlessly hide the keyguard as your application 835 * moves in and out of the foreground and does not require that any special 836 * permissions be requested. 837 */ 838 @Deprecated 839 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) exitKeyguardSecurely(final OnKeyguardExitResult callback)840 public void exitKeyguardSecurely(final OnKeyguardExitResult callback) { 841 try { 842 mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() { 843 public void onKeyguardExitResult(boolean success) throws RemoteException { 844 if (callback != null) { 845 callback.onKeyguardExitResult(success); 846 } 847 } 848 }); 849 } catch (RemoteException e) { 850 851 } 852 } 853 854 /** @hide */ 855 @VisibleForTesting checkInitialLockMethodUsage()856 public boolean checkInitialLockMethodUsage() { 857 if (!hasPermission(Manifest.permission.SET_INITIAL_LOCK)) { 858 throw new SecurityException("Requires SET_INITIAL_LOCK permission."); 859 } 860 return true; 861 } 862 hasPermission(String permission)863 private boolean hasPermission(String permission) { 864 return PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( 865 permission); 866 } 867 868 /** 869 * Determine if a given password is valid based off its lock type and expected complexity level. 870 * 871 * @param lockType - type of lock as specified in {@link LockTypes} 872 * @param password - password to validate; this has the same encoding 873 * as the output of String#getBytes 874 * @param complexity - complexity level imposed by the requester 875 * as defined in {@code DevicePolicyManager.PasswordComplexity} 876 * @return {@code true} if the password is valid, false otherwise 877 * @hide 878 */ 879 @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) 880 @SystemApi isValidLockPasswordComplexity(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)881 public boolean isValidLockPasswordComplexity(@LockTypes int lockType, @NonNull byte[] password, 882 @PasswordComplexity int complexity) { 883 if (!checkInitialLockMethodUsage()) { 884 return false; 885 } 886 complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); 887 // TODO: b/131755827 add devicePolicyManager support for Auto 888 DevicePolicyManager devicePolicyManager = 889 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 890 PasswordMetrics adminMetrics = 891 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); 892 // Check if the password fits the mold of a pin or pattern. 893 boolean isPinOrPattern = lockType != PASSWORD; 894 895 return PasswordMetrics.validatePassword( 896 adminMetrics, complexity, isPinOrPattern, password).size() == 0; 897 } 898 899 /** 900 * Determine the minimum allowable length for a lock type for a given complexity level. 901 * 902 * @param isPin - whether this is a PIN-type password (only digits) 903 * @param complexity - complexity level imposed by the requester 904 * as defined in {@code DevicePolicyManager.PasswordComplexity} 905 * @return minimum allowable password length 906 * @hide 907 */ 908 @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) 909 @SystemApi getMinLockLength(boolean isPin, @PasswordComplexity int complexity)910 public int getMinLockLength(boolean isPin, @PasswordComplexity int complexity) { 911 if (!checkInitialLockMethodUsage()) { 912 return -1; 913 } 914 complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); 915 // TODO: b/131755827 add devicePolicyManager support for Auto 916 DevicePolicyManager devicePolicyManager = 917 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 918 PasswordMetrics adminMetrics = 919 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); 920 PasswordMetrics minMetrics = 921 PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity); 922 return minMetrics.length; 923 } 924 925 /** 926 * Set the lockscreen password after validating against its expected complexity level. 927 * 928 * Below {@link android.os.Build.VERSION_CODES#S_V2}, this API will only work 929 * when {@link PackageManager.FEATURE_AUTOMOTIVE} is present. 930 * @param lockType - type of lock as specified in {@link LockTypes} 931 * @param password - password to validate; this has the same encoding 932 * as the output of String#getBytes 933 * @param complexity - complexity level imposed by the requester 934 * as defined in {@code DevicePolicyManager.PasswordComplexity} 935 * @return {@code true} if the lock is successfully set, false otherwise 936 * @hide 937 */ 938 @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) 939 @SystemApi setLock(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)940 public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, 941 @PasswordComplexity int complexity) { 942 if (!checkInitialLockMethodUsage()) { 943 return false; 944 } 945 946 int userId = mContext.getUserId(); 947 if (isDeviceSecure(userId)) { 948 Log.e(TAG, "Password already set, rejecting call to setLock"); 949 return false; 950 } 951 if (!isValidLockPasswordComplexity(lockType, password, complexity)) { 952 Log.e(TAG, "Password is not valid, rejecting call to setLock"); 953 return false; 954 } 955 boolean success; 956 try { 957 LockscreenCredential credential = createLockscreenCredential( 958 lockType, password); 959 success = mLockPatternUtils.setLockCredential( 960 credential, 961 /* savedPassword= */ LockscreenCredential.createNone(), 962 userId); 963 } catch (Exception e) { 964 Log.e(TAG, "Save lock exception", e); 965 success = false; 966 } finally { 967 Arrays.fill(password, (byte) 0); 968 } 969 return success; 970 } 971 972 /** 973 * Create a weak escrow token for the current user, which can later be used to unlock FBE 974 * or change user password. 975 * 976 * After adding, if the user currently has a secure lockscreen, they will need to perform a 977 * confirm credential operation in order to activate the token for future use. If the user 978 * has no secure lockscreen, then the token is activated immediately. 979 * 980 * If the user changes or removes the lockscreen password, any activated weak escrow token will 981 * be removed. 982 * 983 * @return a unique 64-bit token handle which is needed to refer to this token later. 984 * @hide 985 */ 986 @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) 987 @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) 988 @SystemApi addWeakEscrowToken(@onNull byte[] token, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull WeakEscrowTokenActivatedListener listener)989 public long addWeakEscrowToken(@NonNull byte[] token, @NonNull UserHandle user, 990 @NonNull @CallbackExecutor Executor executor, 991 @NonNull WeakEscrowTokenActivatedListener listener) { 992 Objects.requireNonNull(token, "Token cannot be null."); 993 Objects.requireNonNull(user, "User cannot be null."); 994 Objects.requireNonNull(executor, "Executor cannot be null."); 995 Objects.requireNonNull(listener, "Listener cannot be null."); 996 int userId = user.getIdentifier(); 997 IWeakEscrowTokenActivatedListener internalListener = 998 new IWeakEscrowTokenActivatedListener.Stub() { 999 @Override 1000 public void onWeakEscrowTokenActivated(long handle, int userId) { 1001 UserHandle user = UserHandle.of(userId); 1002 final long restoreToken = Binder.clearCallingIdentity(); 1003 try { 1004 executor.execute(() -> listener.onWeakEscrowTokenActivated(handle, user)); 1005 } finally { 1006 Binder.restoreCallingIdentity(restoreToken); 1007 } 1008 Log.i(TAG, "Weak escrow token activated."); 1009 } 1010 }; 1011 return mLockPatternUtils.addWeakEscrowToken(token, userId, internalListener); 1012 } 1013 1014 /** 1015 * Remove a weak escrow token. 1016 * 1017 * @return {@code true} if the given handle refers to a valid weak token previously returned 1018 * from {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise. 1019 * @hide 1020 */ 1021 @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) 1022 @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) 1023 @SystemApi removeWeakEscrowToken(long handle, @NonNull UserHandle user)1024 public boolean removeWeakEscrowToken(long handle, @NonNull UserHandle user) { 1025 Objects.requireNonNull(user, "User cannot be null."); 1026 return mLockPatternUtils.removeWeakEscrowToken(handle, user.getIdentifier()); 1027 } 1028 1029 /** 1030 * Check if the given weak escrow token is active or not. 1031 * @hide 1032 */ 1033 @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) 1034 @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) 1035 @SystemApi isWeakEscrowTokenActive(long handle, @NonNull UserHandle user)1036 public boolean isWeakEscrowTokenActive(long handle, @NonNull UserHandle user) { 1037 Objects.requireNonNull(user, "User cannot be null."); 1038 return mLockPatternUtils.isWeakEscrowTokenActive(handle, user.getIdentifier()); 1039 } 1040 1041 /** 1042 * Check if the given weak escrow token is validate. 1043 * @hide 1044 */ 1045 @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) 1046 @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) 1047 @SystemApi isWeakEscrowTokenValid(long handle, @NonNull byte[] token, @NonNull UserHandle user)1048 public boolean isWeakEscrowTokenValid(long handle, @NonNull byte[] token, 1049 @NonNull UserHandle user) { 1050 Objects.requireNonNull(token, "Token cannot be null."); 1051 Objects.requireNonNull(user, "User cannot be null."); 1052 return mLockPatternUtils.isWeakEscrowTokenValid(handle, token, user.getIdentifier()); 1053 } 1054 1055 /** 1056 * Register the given WeakEscrowTokenRemovedListener. 1057 * 1058 * @return {@code true} if the listener is registered successfully, return false otherwise. 1059 * @hide 1060 */ 1061 @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) 1062 @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) 1063 @SystemApi registerWeakEscrowTokenRemovedListener( @onNull @allbackExecutor Executor executor, @NonNull WeakEscrowTokenRemovedListener listener)1064 public boolean registerWeakEscrowTokenRemovedListener( 1065 @NonNull @CallbackExecutor Executor executor, 1066 @NonNull WeakEscrowTokenRemovedListener listener) { 1067 Objects.requireNonNull(listener, "Listener cannot be null."); 1068 Objects.requireNonNull(executor, "Executor cannot be null."); 1069 Preconditions.checkArgument(!mListeners.containsKey(listener), 1070 "Listener already registered: %s", listener); 1071 IWeakEscrowTokenRemovedListener internalListener = 1072 new IWeakEscrowTokenRemovedListener.Stub() { 1073 @Override 1074 public void onWeakEscrowTokenRemoved(long handle, int userId) { 1075 UserHandle user = UserHandle.of(userId); 1076 final long token = Binder.clearCallingIdentity(); 1077 try { 1078 executor.execute(() -> listener.onWeakEscrowTokenRemoved(handle, user)); 1079 } finally { 1080 Binder.restoreCallingIdentity(token); 1081 } 1082 } 1083 }; 1084 if (mLockPatternUtils.registerWeakEscrowTokenRemovedListener(internalListener)) { 1085 mListeners.put(listener, internalListener); 1086 return true; 1087 } else { 1088 Log.e(TAG, "Listener failed to register"); 1089 return false; 1090 } 1091 } 1092 1093 /** 1094 * Unregister the given WeakEscrowTokenRemovedListener. 1095 * 1096 * @return {@code true} if the listener is unregistered successfully, return false otherwise. 1097 * @hide 1098 */ 1099 @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) 1100 @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) 1101 @SystemApi unregisterWeakEscrowTokenRemovedListener( @onNull WeakEscrowTokenRemovedListener listener)1102 public boolean unregisterWeakEscrowTokenRemovedListener( 1103 @NonNull WeakEscrowTokenRemovedListener listener) { 1104 Objects.requireNonNull(listener, "Listener cannot be null."); 1105 IWeakEscrowTokenRemovedListener internalListener = mListeners.get(listener); 1106 Preconditions.checkArgument(internalListener != null, "Listener was not registered"); 1107 if (mLockPatternUtils.unregisterWeakEscrowTokenRemovedListener(internalListener)) { 1108 mListeners.remove(listener); 1109 return true; 1110 } else { 1111 Log.e(TAG, "Listener failed to unregister."); 1112 return false; 1113 } 1114 } 1115 1116 /** 1117 * Set the lockscreen password to {@code newPassword} after validating the current password 1118 * against {@code currentPassword}. 1119 * <p>If no password is currently set, {@code currentPassword} should be set to {@code null}. 1120 * <p>To clear the current password, {@code newPassword} should be set to {@code null}. 1121 * 1122 * @return {@code true} if password successfully set. 1123 * 1124 * @throws IllegalArgumentException if {@code newLockType} or {@code currentLockType} 1125 * is invalid. 1126 * 1127 * @hide 1128 */ 1129 @TestApi 1130 @RequiresPermission(anyOf = { 1131 Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, 1132 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE 1133 }) setLock(@ockTypes int newLockType, @Nullable byte[] newPassword, @LockTypes int currentLockType, @Nullable byte[] currentPassword)1134 public boolean setLock(@LockTypes int newLockType, @Nullable byte[] newPassword, 1135 @LockTypes int currentLockType, @Nullable byte[] currentPassword) { 1136 final int userId = mContext.getUserId(); 1137 LockscreenCredential currentCredential = createLockscreenCredential( 1138 currentLockType, currentPassword); 1139 LockscreenCredential newCredential = createLockscreenCredential( 1140 newLockType, newPassword); 1141 return mLockPatternUtils.setLockCredential(newCredential, currentCredential, userId); 1142 } 1143 1144 /** 1145 * Verifies the current lock credentials against {@code password}. 1146 * <p>To check if no password is set, {@code password} should be set to {@code null}. 1147 * 1148 * @return {@code true} if credentials match 1149 * 1150 * @throws IllegalArgumentException if {@code lockType} is invalid. 1151 * 1152 * @hide 1153 */ 1154 @TestApi 1155 @RequiresPermission(anyOf = { 1156 Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, 1157 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE 1158 }) checkLock(@ockTypes int lockType, @Nullable byte[] password)1159 public boolean checkLock(@LockTypes int lockType, @Nullable byte[] password) { 1160 final LockscreenCredential credential = createLockscreenCredential( 1161 lockType, password); 1162 final VerifyCredentialResponse response = mLockPatternUtils.verifyCredential( 1163 credential, mContext.getUserId(), /* flags= */ 0); 1164 if (response == null) { 1165 return false; 1166 } 1167 return response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK; 1168 } 1169 1170 /** Starts a session to verify lockscreen credentials provided by a remote device. 1171 * 1172 * The session and corresponding public key will be removed when 1173 * {@code validateRemoteLockScreen} provides a correct guess or after 10 minutes of inactivity. 1174 * 1175 * @return information necessary to perform remote lock screen credentials check, including 1176 1177 * short lived public key used to send encrypted guess and lock screen type. 1178 * 1179 * @throws IllegalStateException if lock screen is not set 1180 * 1181 * @hide 1182 */ 1183 @SystemApi 1184 @RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN) 1185 @NonNull startRemoteLockscreenValidation()1186 public RemoteLockscreenValidationSession startRemoteLockscreenValidation() { 1187 return mLockPatternUtils.startRemoteLockscreenValidation(); 1188 } 1189 1190 /** 1191 * Verifies credentials guess from a remote device. 1192 * 1193 * <p>Secret must be encrypted using {@code SecureBox} library 1194 * with public key from {@code RemoteLockscreenValidationSession} 1195 * and header set to {@code "encrypted_remote_credentials"} in UTF-8 encoding. 1196 * 1197 * @throws IllegalStateException if there was a decryption error. 1198 * 1199 * @hide 1200 */ 1201 @SystemApi 1202 @RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN) 1203 @NonNull validateRemoteLockscreen( @onNull byte[] encryptedCredential)1204 public RemoteLockscreenValidationResult validateRemoteLockscreen( 1205 @NonNull byte[] encryptedCredential) { 1206 return mLockPatternUtils.validateRemoteLockscreen(encryptedCredential); 1207 } 1208 createLockscreenCredential( @ockTypes int lockType, @Nullable byte[] password)1209 private LockscreenCredential createLockscreenCredential( 1210 @LockTypes int lockType, @Nullable byte[] password) { 1211 if (password == null) { 1212 return LockscreenCredential.createNone(); 1213 } 1214 switch (lockType) { 1215 case PASSWORD: 1216 CharSequence passwordStr = new String(password, Charset.forName("UTF-8")); 1217 return LockscreenCredential.createPassword(passwordStr); 1218 case PIN: 1219 CharSequence pinStr = new String(password); 1220 return LockscreenCredential.createPin(pinStr); 1221 case PATTERN: 1222 List<LockPatternView.Cell> pattern = 1223 LockPatternUtils.byteArrayToPattern(password); 1224 return LockscreenCredential.createPattern(pattern); 1225 default: 1226 throw new IllegalArgumentException("Unknown lock type " + lockType); 1227 } 1228 } 1229 1230 /** 1231 * Listener for keyguard locked state changes. 1232 */ 1233 @FunctionalInterface 1234 public interface KeyguardLockedStateListener { 1235 /** 1236 * Callback function that executes when the keyguard locked state changes. 1237 */ onKeyguardLockedStateChanged(boolean isKeyguardLocked)1238 void onKeyguardLockedStateChanged(boolean isKeyguardLocked); 1239 } 1240 1241 /** 1242 * Registers a listener to execute when the keyguard locked state changes. 1243 * 1244 * @param listener The listener to add to receive keyguard locked state changes. 1245 * 1246 * @see #isKeyguardLocked() 1247 * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener) 1248 */ 1249 @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) addKeyguardLockedStateListener(@onNull @allbackExecutor Executor executor, @NonNull KeyguardLockedStateListener listener)1250 public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor, 1251 @NonNull KeyguardLockedStateListener listener) { 1252 synchronized (mKeyguardLockedStateListeners) { 1253 mKeyguardLockedStateListeners.put(listener, executor); 1254 if (mKeyguardLockedStateListeners.size() > 1) { 1255 return; 1256 } 1257 try { 1258 mWM.addKeyguardLockedStateListener(mIKeyguardLockedStateListener); 1259 } catch (RemoteException e) { 1260 throw e.rethrowFromSystemServer(); 1261 } 1262 } 1263 } 1264 1265 /** 1266 * Unregisters a listener that executes when the keyguard locked state changes. 1267 * 1268 * @param listener The listener to remove. 1269 * 1270 * @see #isKeyguardLocked() 1271 * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener) 1272 */ 1273 @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) removeKeyguardLockedStateListener(@onNull KeyguardLockedStateListener listener)1274 public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) { 1275 synchronized (mKeyguardLockedStateListeners) { 1276 mKeyguardLockedStateListeners.remove(listener); 1277 if (!mKeyguardLockedStateListeners.isEmpty()) { 1278 return; 1279 } 1280 try { 1281 mWM.removeKeyguardLockedStateListener(mIKeyguardLockedStateListener); 1282 } catch (RemoteException e) { 1283 throw e.rethrowFromSystemServer(); 1284 } 1285 } 1286 } 1287 } 1288