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.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresFeature; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SystemApi; 26 import android.annotation.SystemService; 27 import android.annotation.TestApi; 28 import android.app.admin.DevicePolicyManager; 29 import android.app.admin.DevicePolicyManager.PasswordComplexity; 30 import android.app.admin.PasswordMetrics; 31 import android.app.trust.ITrustManager; 32 import android.compat.annotation.UnsupportedAppUsage; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.pm.PackageManager; 36 import android.content.pm.ResolveInfo; 37 import android.os.Binder; 38 import android.os.Build; 39 import android.os.IBinder; 40 import android.os.RemoteException; 41 import android.os.ServiceManager; 42 import android.os.ServiceManager.ServiceNotFoundException; 43 import android.provider.Settings; 44 import android.service.persistentdata.IPersistentDataBlockService; 45 import android.util.Log; 46 import android.view.IOnKeyguardExitResult; 47 import android.view.IWindowManager; 48 import android.view.WindowManager.LayoutParams; 49 import android.view.WindowManagerGlobal; 50 51 import com.android.internal.policy.IKeyguardDismissCallback; 52 import com.android.internal.widget.LockPatternUtils; 53 import com.android.internal.widget.LockPatternView; 54 import com.android.internal.widget.LockscreenCredential; 55 import com.android.internal.widget.VerifyCredentialResponse; 56 57 import java.nio.charset.Charset; 58 import java.util.Arrays; 59 import java.util.List; 60 61 /** 62 * Class that can be used to lock and unlock the keyguard. The 63 * actual class to control the keyguard locking is 64 * {@link android.app.KeyguardManager.KeyguardLock}. 65 */ 66 @SystemService(Context.KEYGUARD_SERVICE) 67 public class KeyguardManager { 68 69 private static final String TAG = "KeyguardManager"; 70 71 private final Context mContext; 72 private final IWindowManager mWM; 73 private final IActivityManager mAm; 74 private final ITrustManager mTrustManager; 75 private final INotificationManager mNotificationManager; 76 77 /** 78 * Intent used to prompt user for device credentials. 79 * @hide 80 */ 81 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL = 82 "android.app.action.CONFIRM_DEVICE_CREDENTIAL"; 83 84 /** 85 * Intent used to prompt user for device credentials. 86 * @hide 87 */ 88 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER = 89 "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER"; 90 91 /** 92 * Intent used to prompt user for factory reset credentials. 93 * @hide 94 */ 95 public static final String ACTION_CONFIRM_FRP_CREDENTIAL = 96 "android.app.action.CONFIRM_FRP_CREDENTIAL"; 97 98 /** 99 * A CharSequence dialog title to show to the user when used with a 100 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 101 * @hide 102 */ 103 public static final String EXTRA_TITLE = "android.app.extra.TITLE"; 104 105 /** 106 * A CharSequence description to show to the user when used with 107 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 108 * @hide 109 */ 110 public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION"; 111 112 /** 113 * A CharSequence description to show to the user on the alternate button when used with 114 * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}. 115 * @hide 116 */ 117 public static final String EXTRA_ALTERNATE_BUTTON_LABEL = 118 "android.app.extra.ALTERNATE_BUTTON_LABEL"; 119 120 /** 121 * Result code returned by the activity started by 122 * {@link #createConfirmFactoryResetCredentialIntent} indicating that the user clicked the 123 * alternate button. 124 * 125 * @hide 126 */ 127 public static final int RESULT_ALTERNATE = 1; 128 129 /** 130 * 131 * If this is set, check device policy for allowed biometrics when the user is authenticating. 132 * This should only be used in the context of managed profiles. 133 * 134 * @hide 135 */ 136 public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm"; 137 138 /** 139 * 140 * Password lock type, see {@link #setLock} 141 * 142 * @hide 143 */ 144 @SystemApi 145 public static final int PASSWORD = 0; 146 147 /** 148 * 149 * Pin lock type, see {@link #setLock} 150 * 151 * @hide 152 */ 153 @SystemApi 154 public static final int PIN = 1; 155 156 /** 157 * 158 * Pattern lock type, see {@link #setLock} 159 * 160 * @hide 161 */ 162 @SystemApi 163 public static final int PATTERN = 2; 164 165 /** 166 * Available lock types 167 */ 168 @IntDef({ 169 PASSWORD, 170 PIN, 171 PATTERN 172 }) 173 @interface LockTypes {} 174 175 /** 176 * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics 177 * if enrolled) for the current user of the device. The caller is expected to launch this 178 * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 179 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 180 * 181 * @return the intent for launching the activity or null if no password is required. 182 * @deprecated see BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean) 183 */ 184 @Deprecated 185 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description)186 public Intent createConfirmDeviceCredentialIntent(CharSequence title, 187 CharSequence description) { 188 if (!isDeviceSecure()) return null; 189 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL); 190 intent.putExtra(EXTRA_TITLE, title); 191 intent.putExtra(EXTRA_DESCRIPTION, description); 192 193 // explicitly set the package for security 194 intent.setPackage(getSettingsPackageForIntent(intent)); 195 return intent; 196 } 197 198 /** 199 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 200 * for the given user. The caller is expected to launch this activity using 201 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 202 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 203 * 204 * @return the intent for launching the activity or null if no password is required. 205 * 206 * @hide 207 */ createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId)208 public Intent createConfirmDeviceCredentialIntent( 209 CharSequence title, CharSequence description, int userId) { 210 if (!isDeviceSecure(userId)) return null; 211 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); 212 intent.putExtra(EXTRA_TITLE, title); 213 intent.putExtra(EXTRA_DESCRIPTION, description); 214 intent.putExtra(Intent.EXTRA_USER_ID, userId); 215 216 // explicitly set the package for security 217 intent.setPackage(getSettingsPackageForIntent(intent)); 218 219 return intent; 220 } 221 222 /** 223 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 224 * for the given user. The caller is expected to launch this activity using 225 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 226 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 227 * 228 * @param disallowBiometricsIfPolicyExists If true check if the Device Policy Manager has 229 * disabled biometrics on the device. If biometrics are disabled, fall back to PIN/pattern/pass. 230 * 231 * @return the intent for launching the activity or null if no password is required. 232 * 233 * @hide 234 */ createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId, boolean disallowBiometricsIfPolicyExists)235 public Intent createConfirmDeviceCredentialIntent( 236 CharSequence title, CharSequence description, int userId, 237 boolean disallowBiometricsIfPolicyExists) { 238 Intent intent = this.createConfirmDeviceCredentialIntent(title, description, userId); 239 intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, 240 disallowBiometricsIfPolicyExists); 241 return intent; 242 } 243 244 /** 245 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 246 * for the previous owner of the device. The caller is expected to launch this activity using 247 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 248 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 249 * 250 * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon 251 * clicking this button, the activity returns 252 * {@link #RESULT_ALTERNATE} 253 * 254 * @return the intent for launching the activity or null if the previous owner of the device 255 * did not set a credential. 256 * @throws UnsupportedOperationException if the device does not support factory reset 257 * credentials 258 * @throws IllegalStateException if the device has already been provisioned 259 * @hide 260 */ 261 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 262 @SystemApi createConfirmFactoryResetCredentialIntent( CharSequence title, CharSequence description, CharSequence alternateButtonLabel)263 public Intent createConfirmFactoryResetCredentialIntent( 264 CharSequence title, CharSequence description, CharSequence alternateButtonLabel) { 265 if (!LockPatternUtils.frpCredentialEnabled(mContext)) { 266 Log.w(TAG, "Factory reset credentials not supported."); 267 throw new UnsupportedOperationException("not supported on this device"); 268 } 269 270 // Cannot verify credential if the device is provisioned 271 if (Settings.Global.getInt(mContext.getContentResolver(), 272 Settings.Global.DEVICE_PROVISIONED, 0) != 0) { 273 Log.e(TAG, "Factory reset credential cannot be verified after provisioning."); 274 throw new IllegalStateException("must not be provisioned yet"); 275 } 276 277 // Make sure we have a credential 278 try { 279 IPersistentDataBlockService pdb = IPersistentDataBlockService.Stub.asInterface( 280 ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE)); 281 if (pdb == null) { 282 Log.e(TAG, "No persistent data block service"); 283 throw new UnsupportedOperationException("not supported on this device"); 284 } 285 // The following will throw an UnsupportedOperationException if the device does not 286 // support factory reset credentials (or something went wrong retrieving it). 287 if (!pdb.hasFrpCredentialHandle()) { 288 Log.i(TAG, "The persistent data block does not have a factory reset credential."); 289 return null; 290 } 291 } catch (RemoteException e) { 292 throw e.rethrowFromSystemServer(); 293 } 294 295 Intent intent = new Intent(ACTION_CONFIRM_FRP_CREDENTIAL); 296 intent.putExtra(EXTRA_TITLE, title); 297 intent.putExtra(EXTRA_DESCRIPTION, description); 298 intent.putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel); 299 300 // explicitly set the package for security 301 intent.setPackage(getSettingsPackageForIntent(intent)); 302 303 return intent; 304 } 305 306 /** 307 * Controls whether notifications can be shown atop a securely locked screen in their full 308 * private form (same as when the device is unlocked). 309 * 310 * <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration. 311 * The result is that private notifications are only shown if all sources allow it. 312 * 313 * @param allow secure notifications can be shown if {@code true}, 314 * secure notifications cannot be shown if {@code false} 315 * @hide 316 */ 317 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 318 @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) 319 @SystemApi setPrivateNotificationsAllowed(boolean allow)320 public void setPrivateNotificationsAllowed(boolean allow) { 321 try { 322 mNotificationManager.setPrivateNotificationsAllowed(allow); 323 } catch (RemoteException e) { 324 throw e.rethrowFromSystemServer(); 325 } 326 } 327 328 /** 329 * Returns whether notifications can be shown atop a securely locked screen in their full 330 * private form (same as when the device is unlocked). 331 * 332 * @return {@code true} if secure notifications can be shown, {@code false} otherwise. 333 * By default, private notifications are allowed. 334 * @hide 335 */ 336 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 337 @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) 338 @SystemApi getPrivateNotificationsAllowed()339 public boolean getPrivateNotificationsAllowed() { 340 try { 341 return mNotificationManager.getPrivateNotificationsAllowed(); 342 } catch (RemoteException e) { 343 throw e.rethrowFromSystemServer(); 344 } 345 } 346 getSettingsPackageForIntent(Intent intent)347 private String getSettingsPackageForIntent(Intent intent) { 348 List<ResolveInfo> resolveInfos = mContext.getPackageManager() 349 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY); 350 for (int i = 0; i < resolveInfos.size(); i++) { 351 return resolveInfos.get(i).activityInfo.packageName; 352 } 353 354 return "com.android.settings"; 355 } 356 357 /** 358 * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows 359 * you to disable / reenable the keyguard. 360 * 361 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 362 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 363 * instead; this allows you to seamlessly hide the keyguard as your application 364 * moves in and out of the foreground and does not require that any special 365 * permissions be requested. 366 */ 367 @Deprecated 368 public class KeyguardLock { 369 private final IBinder mToken = new Binder(); 370 private final String mTag; 371 KeyguardLock(String tag)372 KeyguardLock(String tag) { 373 mTag = tag; 374 } 375 376 /** 377 * Disable the keyguard from showing. If the keyguard is currently 378 * showing, hide it. The keyguard will be prevented from showing again 379 * until {@link #reenableKeyguard()} is called. 380 * 381 * A good place to call this is from {@link android.app.Activity#onResume()} 382 * 383 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 384 * is enabled that requires a password. 385 * 386 * @see #reenableKeyguard() 387 */ 388 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) disableKeyguard()389 public void disableKeyguard() { 390 try { 391 mWM.disableKeyguard(mToken, mTag, mContext.getUserId()); 392 } catch (RemoteException ex) { 393 } 394 } 395 396 /** 397 * Reenable the keyguard. The keyguard will reappear if the previous 398 * call to {@link #disableKeyguard()} caused it to be hidden. 399 * 400 * A good place to call this is from {@link android.app.Activity#onPause()} 401 * 402 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 403 * is enabled that requires a password. 404 * 405 * @see #disableKeyguard() 406 */ 407 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) reenableKeyguard()408 public void reenableKeyguard() { 409 try { 410 mWM.reenableKeyguard(mToken, mContext.getUserId()); 411 } catch (RemoteException ex) { 412 } 413 } 414 } 415 416 /** 417 * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify 418 * caller of result. 419 * 420 * @deprecated Use {@link KeyguardDismissCallback} 421 */ 422 @Deprecated 423 public interface OnKeyguardExitResult { 424 425 /** 426 * @param success True if the user was able to authenticate, false if 427 * not. 428 */ onKeyguardExitResult(boolean success)429 void onKeyguardExitResult(boolean success); 430 } 431 432 /** 433 * Callback passed to 434 * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardDismissCallback)} 435 * to notify caller of result. 436 */ 437 public static abstract class KeyguardDismissCallback { 438 439 /** 440 * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not 441 * available, not showing or when the activity requesting the Keyguard dismissal isn't 442 * showing or isn't showing behind Keyguard. 443 */ onDismissError()444 public void onDismissError() { } 445 446 /** 447 * Called when dismissing Keyguard has succeeded and the device is now unlocked. 448 */ onDismissSucceeded()449 public void onDismissSucceeded() { } 450 451 /** 452 * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the 453 * operation or the bouncer was hidden for some other reason. 454 */ onDismissCancelled()455 public void onDismissCancelled() { } 456 } 457 KeyguardManager(Context context)458 KeyguardManager(Context context) throws ServiceNotFoundException { 459 mContext = context; 460 mWM = WindowManagerGlobal.getWindowManagerService(); 461 mAm = ActivityManager.getService(); 462 mTrustManager = ITrustManager.Stub.asInterface( 463 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE)); 464 mNotificationManager = INotificationManager.Stub.asInterface( 465 ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE)); 466 } 467 468 /** 469 * Enables you to lock or unlock the keyguard. Get an instance of this class by 470 * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 471 * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}. 472 * @param tag A tag that informally identifies who you are (for debugging who 473 * is disabling the keyguard). 474 * 475 * @return A {@link KeyguardLock} handle to use to disable and reenable the 476 * keyguard. 477 * 478 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 479 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 480 * instead; this allows you to seamlessly hide the keyguard as your application 481 * moves in and out of the foreground and does not require that any special 482 * permissions be requested. 483 */ 484 @Deprecated newKeyguardLock(String tag)485 public KeyguardLock newKeyguardLock(String tag) { 486 return new KeyguardLock(tag); 487 } 488 489 /** 490 * Return whether the keyguard is currently locked. 491 * 492 * @return true if keyguard is locked. 493 */ isKeyguardLocked()494 public boolean isKeyguardLocked() { 495 try { 496 return mWM.isKeyguardLocked(); 497 } catch (RemoteException ex) { 498 return false; 499 } 500 } 501 502 /** 503 * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card 504 * is currently locked. 505 * 506 * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states. 507 * 508 * @return true if a PIN, pattern or password is set or a SIM card is locked. 509 */ isKeyguardSecure()510 public boolean isKeyguardSecure() { 511 try { 512 return mWM.isKeyguardSecure(mContext.getUserId()); 513 } catch (RemoteException ex) { 514 return false; 515 } 516 } 517 518 /** 519 * If keyguard screen is showing or in restricted key input mode (i.e. in 520 * keyguard password emergency screen). When in such mode, certain keys, 521 * such as the Home key and the right soft keys, don't work. 522 * 523 * @return true if in keyguard restricted input mode. 524 * @deprecated Use {@link #isKeyguardLocked()} instead. 525 */ inKeyguardRestrictedInputMode()526 public boolean inKeyguardRestrictedInputMode() { 527 return isKeyguardLocked(); 528 } 529 530 /** 531 * Returns whether the device is currently locked and requires a PIN, pattern or 532 * password to unlock. 533 * 534 * @return true if unlocking the device currently requires a PIN, pattern or 535 * password. 536 */ isDeviceLocked()537 public boolean isDeviceLocked() { 538 return isDeviceLocked(mContext.getUserId()); 539 } 540 541 /** 542 * Per-user version of {@link #isDeviceLocked()}. 543 * 544 * @hide 545 */ 546 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) isDeviceLocked(int userId)547 public boolean isDeviceLocked(int userId) { 548 try { 549 return mTrustManager.isDeviceLocked(userId); 550 } catch (RemoteException e) { 551 return false; 552 } 553 } 554 555 /** 556 * Returns whether the device is secured with a PIN, pattern or 557 * password. 558 * 559 * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure. 560 * 561 * @return true if a PIN, pattern or password was set. 562 */ isDeviceSecure()563 public boolean isDeviceSecure() { 564 return isDeviceSecure(mContext.getUserId()); 565 } 566 567 /** 568 * Per-user version of {@link #isDeviceSecure()}. 569 * 570 * @hide 571 */ 572 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isDeviceSecure(int userId)573 public boolean isDeviceSecure(int userId) { 574 try { 575 return mTrustManager.isDeviceSecure(userId); 576 } catch (RemoteException e) { 577 return false; 578 } 579 } 580 581 /** 582 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 583 * be dismissed. 584 * <p> 585 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 586 * method will immediately dismiss the Keyguard without any user interaction. 587 * <p> 588 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 589 * UI so the user can enter their credentials. 590 * <p> 591 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 592 * the screen will turn on when the keyguard is dismissed. 593 * 594 * @param activity The activity requesting the dismissal. The activity must be either visible 595 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 596 * which it would be visible if Keyguard would not be hiding it. If that's not 597 * the case, the request will fail immediately and 598 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 599 * @param callback The callback to be called if the request to dismiss Keyguard was successful 600 * or {@code null} if the caller isn't interested in knowing the result. The 601 * callback will not be invoked if the activity was destroyed before the 602 * callback was received. 603 */ requestDismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback)604 public void requestDismissKeyguard(@NonNull Activity activity, 605 @Nullable KeyguardDismissCallback callback) { 606 requestDismissKeyguard(activity, null /* message */, callback); 607 } 608 609 /** 610 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 611 * be dismissed. 612 * <p> 613 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 614 * method will immediately dismiss the Keyguard without any user interaction. 615 * <p> 616 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 617 * UI so the user can enter their credentials. 618 * <p> 619 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 620 * the screen will turn on when the keyguard is dismissed. 621 * 622 * @param activity The activity requesting the dismissal. The activity must be either visible 623 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 624 * which it would be visible if Keyguard would not be hiding it. If that's not 625 * the case, the request will fail immediately and 626 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 627 * @param message A message that will be shown in the keyguard explaining why the user 628 * would want to dismiss it. 629 * @param callback The callback to be called if the request to dismiss Keyguard was successful 630 * or {@code null} if the caller isn't interested in knowing the result. The 631 * callback will not be invoked if the activity was destroyed before the 632 * callback was received. 633 * @hide 634 */ 635 @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE) 636 @SystemApi requestDismissKeyguard(@onNull Activity activity, @Nullable CharSequence message, @Nullable KeyguardDismissCallback callback)637 public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message, 638 @Nullable KeyguardDismissCallback callback) { 639 ActivityClient.getInstance().dismissKeyguard( 640 activity.getActivityToken(), new IKeyguardDismissCallback.Stub() { 641 @Override 642 public void onDismissError() throws RemoteException { 643 if (callback != null && !activity.isDestroyed()) { 644 activity.mHandler.post(callback::onDismissError); 645 } 646 } 647 648 @Override 649 public void onDismissSucceeded() throws RemoteException { 650 if (callback != null && !activity.isDestroyed()) { 651 activity.mHandler.post(callback::onDismissSucceeded); 652 } 653 } 654 655 @Override 656 public void onDismissCancelled() throws RemoteException { 657 if (callback != null && !activity.isDestroyed()) { 658 activity.mHandler.post(callback::onDismissCancelled); 659 } 660 } 661 }, message); 662 } 663 664 /** 665 * Exit the keyguard securely. The use case for this api is that, after 666 * disabling the keyguard, your app, which was granted permission to 667 * disable the keyguard and show a limited amount of information deemed 668 * safe without the user getting past the keyguard, needs to navigate to 669 * something that is not safe to view without getting past the keyguard. 670 * 671 * This will, if the keyguard is secure, bring up the unlock screen of 672 * the keyguard. 673 * 674 * @param callback Lets you know whether the operation was successful and 675 * it is safe to launch anything that would normally be considered safe 676 * once the user has gotten past the keyguard. 677 678 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 679 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 680 * instead; this allows you to seamlessly hide the keyguard as your application 681 * moves in and out of the foreground and does not require that any special 682 * permissions be requested. 683 */ 684 @Deprecated 685 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) exitKeyguardSecurely(final OnKeyguardExitResult callback)686 public void exitKeyguardSecurely(final OnKeyguardExitResult callback) { 687 try { 688 mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() { 689 public void onKeyguardExitResult(boolean success) throws RemoteException { 690 if (callback != null) { 691 callback.onKeyguardExitResult(success); 692 } 693 } 694 }); 695 } catch (RemoteException e) { 696 697 } 698 } 699 checkInitialLockMethodUsage()700 private boolean checkInitialLockMethodUsage() { 701 if (!hasPermission(Manifest.permission.SET_INITIAL_LOCK)) { 702 throw new SecurityException("Requires SET_INITIAL_LOCK permission."); 703 } 704 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 705 } 706 hasPermission(String permission)707 private boolean hasPermission(String permission) { 708 return PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( 709 permission); 710 } 711 712 /** 713 * Determine if a given password is valid based off its lock type and expected complexity level. 714 * 715 * @param lockType - type of lock as specified in {@link LockTypes} 716 * @param password - password to validate; this has the same encoding 717 * as the output of String#getBytes 718 * @param complexity - complexity level imposed by the requester 719 * as defined in {@code DevicePolicyManager.PasswordComplexity} 720 * @return true if the password is valid, false otherwise 721 * @hide 722 */ 723 @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) 724 @SystemApi isValidLockPasswordComplexity(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)725 public boolean isValidLockPasswordComplexity(@LockTypes int lockType, @NonNull byte[] password, 726 @PasswordComplexity int complexity) { 727 if (!checkInitialLockMethodUsage()) { 728 return false; 729 } 730 complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); 731 // TODO: b/131755827 add devicePolicyManager support for Auto 732 DevicePolicyManager devicePolicyManager = 733 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 734 PasswordMetrics adminMetrics = 735 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); 736 // Check if the password fits the mold of a pin or pattern. 737 boolean isPinOrPattern = lockType != PASSWORD; 738 739 return PasswordMetrics.validatePassword( 740 adminMetrics, complexity, isPinOrPattern, password).size() == 0; 741 } 742 743 /** 744 * Determine the minimum allowable length for a lock type for a given complexity level. 745 * 746 * @param isPin - whether this is a PIN-type password (only digits) 747 * @param complexity - complexity level imposed by the requester 748 * as defined in {@code DevicePolicyManager.PasswordComplexity} 749 * @return minimum allowable password length 750 * @hide 751 */ 752 @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) 753 @SystemApi getMinLockLength(boolean isPin, @PasswordComplexity int complexity)754 public int getMinLockLength(boolean isPin, @PasswordComplexity int complexity) { 755 if (!checkInitialLockMethodUsage()) { 756 return -1; 757 } 758 complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); 759 // TODO: b/131755827 add devicePolicyManager support for Auto 760 DevicePolicyManager devicePolicyManager = 761 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 762 PasswordMetrics adminMetrics = 763 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); 764 PasswordMetrics minMetrics = 765 PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity); 766 return minMetrics.length; 767 } 768 769 /** 770 * Set the lockscreen password after validating against its expected complexity level. 771 * 772 * @param lockType - type of lock as specified in {@link LockTypes} 773 * @param password - password to validate; this has the same encoding 774 * as the output of String#getBytes 775 * @param complexity - complexity level imposed by the requester 776 * as defined in {@code DevicePolicyManager.PasswordComplexity} 777 * @return true if the lock is successfully set, false otherwise 778 * @hide 779 */ 780 @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) 781 @SystemApi setLock(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)782 public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, 783 @PasswordComplexity int complexity) { 784 if (!checkInitialLockMethodUsage()) { 785 return false; 786 } 787 788 LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); 789 int userId = mContext.getUserId(); 790 if (isDeviceSecure(userId)) { 791 Log.e(TAG, "Password already set, rejecting call to setLock"); 792 return false; 793 } 794 if (!isValidLockPasswordComplexity(lockType, password, complexity)) { 795 Log.e(TAG, "Password is not valid, rejecting call to setLock"); 796 return false; 797 } 798 boolean success; 799 try { 800 LockscreenCredential credential = createLockscreenCredential( 801 lockType, password); 802 success = lockPatternUtils.setLockCredential( 803 credential, 804 /* savedPassword= */ LockscreenCredential.createNone(), 805 userId); 806 } catch (Exception e) { 807 Log.e(TAG, "Save lock exception", e); 808 success = false; 809 } finally { 810 Arrays.fill(password, (byte) 0); 811 } 812 return success; 813 } 814 815 /** 816 * Set the lockscreen password to {@code newPassword} after validating the current password 817 * against {@code currentPassword}. 818 * <p>If no password is currently set, {@code currentPassword} should be set to {@code null}. 819 * <p>To clear the current password, {@code newPassword} should be set to {@code null}. 820 * 821 * @return {@code true} if password successfully set. 822 * 823 * @throws IllegalArgumentException if {@code newLockType} or {@code currentLockType} 824 * is invalid. 825 * 826 * @hide 827 */ 828 @TestApi 829 @RequiresPermission(anyOf = { 830 Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, 831 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE 832 }) setLock(@ockTypes int newLockType, @Nullable byte[] newPassword, @LockTypes int currentLockType, @Nullable byte[] currentPassword)833 public boolean setLock(@LockTypes int newLockType, @Nullable byte[] newPassword, 834 @LockTypes int currentLockType, @Nullable byte[] currentPassword) { 835 final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); 836 final int userId = mContext.getUserId(); 837 LockscreenCredential currentCredential = createLockscreenCredential( 838 currentLockType, currentPassword); 839 LockscreenCredential newCredential = createLockscreenCredential( 840 newLockType, newPassword); 841 return lockPatternUtils.setLockCredential(newCredential, currentCredential, userId); 842 } 843 844 /** 845 * Verifies the current lock credentials against {@code password}. 846 * <p>To check if no password is set, {@code password} should be set to {@code null}. 847 * 848 * @return {@code true} if credentials match 849 * 850 * @throws IllegalArgumentException if {@code lockType} is invalid. 851 * 852 * @hide 853 */ 854 @TestApi 855 @RequiresPermission(anyOf = { 856 Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, 857 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE 858 }) checkLock(@ockTypes int lockType, @Nullable byte[] password)859 public boolean checkLock(@LockTypes int lockType, @Nullable byte[] password) { 860 final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); 861 final LockscreenCredential credential = createLockscreenCredential( 862 lockType, password); 863 final VerifyCredentialResponse response = lockPatternUtils.verifyCredential( 864 credential, mContext.getUserId(), /* flags= */ 0); 865 if (response == null) { 866 return false; 867 } 868 return response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK; 869 } 870 createLockscreenCredential( @ockTypes int lockType, @Nullable byte[] password)871 private LockscreenCredential createLockscreenCredential( 872 @LockTypes int lockType, @Nullable byte[] password) { 873 if (password == null) { 874 return LockscreenCredential.createNone(); 875 } 876 switch (lockType) { 877 case PASSWORD: 878 CharSequence passwordStr = new String(password, Charset.forName("UTF-8")); 879 return LockscreenCredential.createPassword(passwordStr); 880 case PIN: 881 CharSequence pinStr = new String(password); 882 return LockscreenCredential.createPin(pinStr); 883 case PATTERN: 884 List<LockPatternView.Cell> pattern = 885 LockPatternUtils.byteArrayToPattern(password); 886 return LockscreenCredential.createPattern(pattern); 887 default: 888 throw new IllegalArgumentException("Unknown lock type " + lockType); 889 } 890 } 891 } 892