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.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresFeature; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemApi; 25 import android.annotation.SystemService; 26 import android.app.trust.ITrustManager; 27 import android.compat.annotation.UnsupportedAppUsage; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.PackageManager; 31 import android.content.pm.ResolveInfo; 32 import android.hardware.biometrics.BiometricPrompt; 33 import android.os.Binder; 34 import android.os.Build; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.os.RemoteException; 38 import android.os.ServiceManager; 39 import android.os.ServiceManager.ServiceNotFoundException; 40 import android.provider.Settings; 41 import android.service.persistentdata.IPersistentDataBlockService; 42 import android.util.Log; 43 import android.view.IOnKeyguardExitResult; 44 import android.view.IWindowManager; 45 import android.view.WindowManager.LayoutParams; 46 import android.view.WindowManagerGlobal; 47 48 import com.android.internal.policy.IKeyguardDismissCallback; 49 import com.android.internal.widget.LockPatternUtils; 50 51 import java.util.List; 52 53 /** 54 * Class that can be used to lock and unlock the keyguard. The 55 * actual class to control the keyguard locking is 56 * {@link android.app.KeyguardManager.KeyguardLock}. 57 */ 58 @SystemService(Context.KEYGUARD_SERVICE) 59 public class KeyguardManager { 60 61 private static final String TAG = "KeyguardManager"; 62 63 private final Context mContext; 64 private final IWindowManager mWM; 65 private final IActivityManager mAm; 66 private final ITrustManager mTrustManager; 67 private final INotificationManager mNotificationManager; 68 69 /** 70 * Intent used to prompt user for device credentials. 71 * @hide 72 */ 73 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL = 74 "android.app.action.CONFIRM_DEVICE_CREDENTIAL"; 75 76 /** 77 * Intent used to prompt user for device credentials. 78 * @hide 79 */ 80 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER = 81 "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER"; 82 83 /** 84 * Intent used to prompt user for factory reset credentials. 85 * @hide 86 */ 87 public static final String ACTION_CONFIRM_FRP_CREDENTIAL = 88 "android.app.action.CONFIRM_FRP_CREDENTIAL"; 89 90 /** 91 * @hide 92 */ 93 public static final String EXTRA_BIOMETRIC_PROMPT_BUNDLE = 94 "android.app.extra.BIOMETRIC_PROMPT_BUNDLE"; 95 96 /** 97 * A CharSequence dialog title to show to the user when used with a 98 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 99 * @hide 100 */ 101 public static final String EXTRA_TITLE = "android.app.extra.TITLE"; 102 103 /** 104 * A CharSequence description to show to the user when used with 105 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 106 * @hide 107 */ 108 public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION"; 109 110 /** 111 * A CharSequence description to show to the user on the alternate button when used with 112 * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}. 113 * @hide 114 */ 115 public static final String EXTRA_ALTERNATE_BUTTON_LABEL = 116 "android.app.extra.ALTERNATE_BUTTON_LABEL"; 117 118 /** 119 * Result code returned by the activity started by 120 * {@link #createConfirmFactoryResetCredentialIntent} indicating that the user clicked the 121 * alternate button. 122 * 123 * @hide 124 */ 125 public static final int RESULT_ALTERNATE = 1; 126 127 /** 128 * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics 129 * if enrolled) for the current user of the device. The caller is expected to launch this 130 * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 131 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 132 * 133 * @return the intent for launching the activity or null if no password is required. 134 * @deprecated see {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)} 135 */ 136 @Deprecated 137 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description)138 public Intent createConfirmDeviceCredentialIntent(CharSequence title, 139 CharSequence description) { 140 if (!isDeviceSecure()) return null; 141 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL); 142 intent.putExtra(EXTRA_TITLE, title); 143 intent.putExtra(EXTRA_DESCRIPTION, description); 144 145 // explicitly set the package for security 146 intent.setPackage(getSettingsPackageForIntent(intent)); 147 return intent; 148 } 149 150 /** 151 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 152 * for the given user. The caller is expected to launch this activity using 153 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 154 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 155 * 156 * @return the intent for launching the activity or null if no password is required. 157 * 158 * @hide 159 */ createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId)160 public Intent createConfirmDeviceCredentialIntent( 161 CharSequence title, CharSequence description, int userId) { 162 if (!isDeviceSecure(userId)) return null; 163 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); 164 intent.putExtra(EXTRA_TITLE, title); 165 intent.putExtra(EXTRA_DESCRIPTION, description); 166 intent.putExtra(Intent.EXTRA_USER_ID, userId); 167 168 // explicitly set the package for security 169 intent.setPackage(getSettingsPackageForIntent(intent)); 170 171 return intent; 172 } 173 174 /** 175 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 176 * for the previous owner of the device. The caller is expected to launch this activity using 177 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 178 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 179 * 180 * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon 181 * clicking this button, the activity returns 182 * {@link #RESULT_ALTERNATE} 183 * 184 * @return the intent for launching the activity or null if the previous owner of the device 185 * did not set a credential. 186 * @throws UnsupportedOperationException if the device does not support factory reset 187 * credentials 188 * @throws IllegalStateException if the device has already been provisioned 189 * @hide 190 */ 191 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 192 @SystemApi createConfirmFactoryResetCredentialIntent( CharSequence title, CharSequence description, CharSequence alternateButtonLabel)193 public Intent createConfirmFactoryResetCredentialIntent( 194 CharSequence title, CharSequence description, CharSequence alternateButtonLabel) { 195 if (!LockPatternUtils.frpCredentialEnabled(mContext)) { 196 Log.w(TAG, "Factory reset credentials not supported."); 197 throw new UnsupportedOperationException("not supported on this device"); 198 } 199 200 // Cannot verify credential if the device is provisioned 201 if (Settings.Global.getInt(mContext.getContentResolver(), 202 Settings.Global.DEVICE_PROVISIONED, 0) != 0) { 203 Log.e(TAG, "Factory reset credential cannot be verified after provisioning."); 204 throw new IllegalStateException("must not be provisioned yet"); 205 } 206 207 // Make sure we have a credential 208 try { 209 IPersistentDataBlockService pdb = IPersistentDataBlockService.Stub.asInterface( 210 ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE)); 211 if (pdb == null) { 212 Log.e(TAG, "No persistent data block service"); 213 throw new UnsupportedOperationException("not supported on this device"); 214 } 215 // The following will throw an UnsupportedOperationException if the device does not 216 // support factory reset credentials (or something went wrong retrieving it). 217 if (!pdb.hasFrpCredentialHandle()) { 218 Log.i(TAG, "The persistent data block does not have a factory reset credential."); 219 return null; 220 } 221 } catch (RemoteException e) { 222 throw e.rethrowFromSystemServer(); 223 } 224 225 Intent intent = new Intent(ACTION_CONFIRM_FRP_CREDENTIAL); 226 intent.putExtra(EXTRA_TITLE, title); 227 intent.putExtra(EXTRA_DESCRIPTION, description); 228 intent.putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel); 229 230 // explicitly set the package for security 231 intent.setPackage(getSettingsPackageForIntent(intent)); 232 233 return intent; 234 } 235 236 /** 237 * Controls whether notifications can be shown atop a securely locked screen in their full 238 * private form (same as when the device is unlocked). 239 * 240 * <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration. 241 * The result is that private notifications are only shown if all sources allow it. 242 * 243 * @param allow secure notifications can be shown if {@code true}, 244 * secure notifications cannot be shown if {@code false} 245 * @hide 246 */ 247 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 248 @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) 249 @SystemApi setPrivateNotificationsAllowed(boolean allow)250 public void setPrivateNotificationsAllowed(boolean allow) { 251 try { 252 mNotificationManager.setPrivateNotificationsAllowed(allow); 253 } catch (RemoteException e) { 254 throw e.rethrowFromSystemServer(); 255 } 256 } 257 258 /** 259 * Returns whether notifications can be shown atop a securely locked screen in their full 260 * private form (same as when the device is unlocked). 261 * 262 * @return {@code true} if secure notifications can be shown, {@code false} otherwise. 263 * By default, private notifications are allowed. 264 * @hide 265 */ 266 @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) 267 @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) 268 @SystemApi getPrivateNotificationsAllowed()269 public boolean getPrivateNotificationsAllowed() { 270 try { 271 return mNotificationManager.getPrivateNotificationsAllowed(); 272 } catch (RemoteException e) { 273 throw e.rethrowFromSystemServer(); 274 } 275 } 276 getSettingsPackageForIntent(Intent intent)277 private String getSettingsPackageForIntent(Intent intent) { 278 List<ResolveInfo> resolveInfos = mContext.getPackageManager() 279 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY); 280 for (int i = 0; i < resolveInfos.size(); i++) { 281 return resolveInfos.get(i).activityInfo.packageName; 282 } 283 284 return "com.android.settings"; 285 } 286 287 /** 288 * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows 289 * you to disable / reenable the keyguard. 290 * 291 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 292 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 293 * instead; this allows you to seamlessly hide the keyguard as your application 294 * moves in and out of the foreground and does not require that any special 295 * permissions be requested. 296 */ 297 @Deprecated 298 public class KeyguardLock { 299 private final IBinder mToken = new Binder(); 300 private final String mTag; 301 KeyguardLock(String tag)302 KeyguardLock(String tag) { 303 mTag = tag; 304 } 305 306 /** 307 * Disable the keyguard from showing. If the keyguard is currently 308 * showing, hide it. The keyguard will be prevented from showing again 309 * until {@link #reenableKeyguard()} is called. 310 * 311 * A good place to call this is from {@link android.app.Activity#onResume()} 312 * 313 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 314 * is enabled that requires a password. 315 * 316 * @see #reenableKeyguard() 317 */ 318 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) disableKeyguard()319 public void disableKeyguard() { 320 try { 321 mWM.disableKeyguard(mToken, mTag, mContext.getUserId()); 322 } catch (RemoteException ex) { 323 } 324 } 325 326 /** 327 * Reenable the keyguard. The keyguard will reappear if the previous 328 * call to {@link #disableKeyguard()} caused it to be hidden. 329 * 330 * A good place to call this is from {@link android.app.Activity#onPause()} 331 * 332 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 333 * is enabled that requires a password. 334 * 335 * @see #disableKeyguard() 336 */ 337 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) reenableKeyguard()338 public void reenableKeyguard() { 339 try { 340 mWM.reenableKeyguard(mToken, mContext.getUserId()); 341 } catch (RemoteException ex) { 342 } 343 } 344 } 345 346 /** 347 * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify 348 * caller of result. 349 * 350 * @deprecated Use {@link KeyguardDismissCallback} 351 */ 352 @Deprecated 353 public interface OnKeyguardExitResult { 354 355 /** 356 * @param success True if the user was able to authenticate, false if 357 * not. 358 */ onKeyguardExitResult(boolean success)359 void onKeyguardExitResult(boolean success); 360 } 361 362 /** 363 * Callback passed to 364 * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardDismissCallback)} 365 * to notify caller of result. 366 */ 367 public static abstract class KeyguardDismissCallback { 368 369 /** 370 * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not 371 * available, not showing or when the activity requesting the Keyguard dismissal isn't 372 * showing or isn't showing behind Keyguard. 373 */ onDismissError()374 public void onDismissError() { } 375 376 /** 377 * Called when dismissing Keyguard has succeeded and the device is now unlocked. 378 */ onDismissSucceeded()379 public void onDismissSucceeded() { } 380 381 /** 382 * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the 383 * operation or the bouncer was hidden for some other reason. 384 */ onDismissCancelled()385 public void onDismissCancelled() { } 386 } 387 KeyguardManager(Context context)388 KeyguardManager(Context context) throws ServiceNotFoundException { 389 mContext = context; 390 mWM = WindowManagerGlobal.getWindowManagerService(); 391 mAm = ActivityManager.getService(); 392 mTrustManager = ITrustManager.Stub.asInterface( 393 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE)); 394 mNotificationManager = INotificationManager.Stub.asInterface( 395 ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE)); 396 } 397 398 /** 399 * Enables you to lock or unlock the keyguard. Get an instance of this class by 400 * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 401 * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}. 402 * @param tag A tag that informally identifies who you are (for debugging who 403 * is disabling the keyguard). 404 * 405 * @return A {@link KeyguardLock} handle to use to disable and reenable the 406 * keyguard. 407 * 408 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 409 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 410 * instead; this allows you to seamlessly hide the keyguard as your application 411 * moves in and out of the foreground and does not require that any special 412 * permissions be requested. 413 */ 414 @Deprecated newKeyguardLock(String tag)415 public KeyguardLock newKeyguardLock(String tag) { 416 return new KeyguardLock(tag); 417 } 418 419 /** 420 * Return whether the keyguard is currently locked. 421 * 422 * @return true if keyguard is locked. 423 */ isKeyguardLocked()424 public boolean isKeyguardLocked() { 425 try { 426 return mWM.isKeyguardLocked(); 427 } catch (RemoteException ex) { 428 return false; 429 } 430 } 431 432 /** 433 * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card 434 * is currently locked. 435 * 436 * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states. 437 * 438 * @return true if a PIN, pattern or password is set or a SIM card is locked. 439 */ isKeyguardSecure()440 public boolean isKeyguardSecure() { 441 try { 442 return mWM.isKeyguardSecure(mContext.getUserId()); 443 } catch (RemoteException ex) { 444 return false; 445 } 446 } 447 448 /** 449 * If keyguard screen is showing or in restricted key input mode (i.e. in 450 * keyguard password emergency screen). When in such mode, certain keys, 451 * such as the Home key and the right soft keys, don't work. 452 * 453 * @return true if in keyguard restricted input mode. 454 * @deprecated Use {@link #isKeyguardLocked()} instead. 455 */ inKeyguardRestrictedInputMode()456 public boolean inKeyguardRestrictedInputMode() { 457 return isKeyguardLocked(); 458 } 459 460 /** 461 * Returns whether the device is currently locked and requires a PIN, pattern or 462 * password to unlock. 463 * 464 * @return true if unlocking the device currently requires a PIN, pattern or 465 * password. 466 */ isDeviceLocked()467 public boolean isDeviceLocked() { 468 return isDeviceLocked(mContext.getUserId()); 469 } 470 471 /** 472 * Per-user version of {@link #isDeviceLocked()}. 473 * 474 * @hide 475 */ 476 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) isDeviceLocked(int userId)477 public boolean isDeviceLocked(int userId) { 478 try { 479 return mTrustManager.isDeviceLocked(userId); 480 } catch (RemoteException e) { 481 return false; 482 } 483 } 484 485 /** 486 * Returns whether the device is secured with a PIN, pattern or 487 * password. 488 * 489 * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure. 490 * 491 * @return true if a PIN, pattern or password was set. 492 */ isDeviceSecure()493 public boolean isDeviceSecure() { 494 return isDeviceSecure(mContext.getUserId()); 495 } 496 497 /** 498 * Per-user version of {@link #isDeviceSecure()}. 499 * 500 * @hide 501 */ 502 @UnsupportedAppUsage isDeviceSecure(int userId)503 public boolean isDeviceSecure(int userId) { 504 try { 505 return mTrustManager.isDeviceSecure(userId); 506 } catch (RemoteException e) { 507 return false; 508 } 509 } 510 511 /** @removed */ 512 @Deprecated dismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback, @Nullable Handler handler)513 public void dismissKeyguard(@NonNull Activity activity, 514 @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) { 515 requestDismissKeyguard(activity, callback); 516 } 517 518 /** 519 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 520 * be dismissed. 521 * <p> 522 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 523 * method will immediately dismiss the Keyguard without any user interaction. 524 * <p> 525 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 526 * UI so the user can enter their credentials. 527 * <p> 528 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 529 * the screen will turn on when the keyguard is dismissed. 530 * 531 * @param activity The activity requesting the dismissal. The activity must be either visible 532 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 533 * which it would be visible if Keyguard would not be hiding it. If that's not 534 * the case, the request will fail immediately and 535 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 536 * @param callback The callback to be called if the request to dismiss Keyguard was successful 537 * or {@code null} if the caller isn't interested in knowing the result. The 538 * callback will not be invoked if the activity was destroyed before the 539 * callback was received. 540 */ requestDismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback)541 public void requestDismissKeyguard(@NonNull Activity activity, 542 @Nullable KeyguardDismissCallback callback) { 543 requestDismissKeyguard(activity, null /* message */, callback); 544 } 545 546 /** 547 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 548 * be dismissed. 549 * <p> 550 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 551 * method will immediately dismiss the Keyguard without any user interaction. 552 * <p> 553 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 554 * UI so the user can enter their credentials. 555 * <p> 556 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 557 * the screen will turn on when the keyguard is dismissed. 558 * 559 * @param activity The activity requesting the dismissal. The activity must be either visible 560 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 561 * which it would be visible if Keyguard would not be hiding it. If that's not 562 * the case, the request will fail immediately and 563 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 564 * @param message A message that will be shown in the keyguard explaining why the user 565 * would want to dismiss it. 566 * @param callback The callback to be called if the request to dismiss Keyguard was successful 567 * or {@code null} if the caller isn't interested in knowing the result. The 568 * callback will not be invoked if the activity was destroyed before the 569 * callback was received. 570 * @hide 571 */ 572 @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE) 573 @SystemApi requestDismissKeyguard(@onNull Activity activity, @Nullable CharSequence message, @Nullable KeyguardDismissCallback callback)574 public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message, 575 @Nullable KeyguardDismissCallback callback) { 576 try { 577 ActivityTaskManager.getService().dismissKeyguard( 578 activity.getActivityToken(), new IKeyguardDismissCallback.Stub() { 579 @Override 580 public void onDismissError() throws RemoteException { 581 if (callback != null && !activity.isDestroyed()) { 582 activity.mHandler.post(callback::onDismissError); 583 } 584 } 585 586 @Override 587 public void onDismissSucceeded() throws RemoteException { 588 if (callback != null && !activity.isDestroyed()) { 589 activity.mHandler.post(callback::onDismissSucceeded); 590 } 591 } 592 593 @Override 594 public void onDismissCancelled() throws RemoteException { 595 if (callback != null && !activity.isDestroyed()) { 596 activity.mHandler.post(callback::onDismissCancelled); 597 } 598 } 599 }, message); 600 } catch (RemoteException e) { 601 throw e.rethrowFromSystemServer(); 602 } 603 } 604 605 /** 606 * Exit the keyguard securely. The use case for this api is that, after 607 * disabling the keyguard, your app, which was granted permission to 608 * disable the keyguard and show a limited amount of information deemed 609 * safe without the user getting past the keyguard, needs to navigate to 610 * something that is not safe to view without getting past the keyguard. 611 * 612 * This will, if the keyguard is secure, bring up the unlock screen of 613 * the keyguard. 614 * 615 * @param callback Lets you know whether the operation was successful and 616 * it is safe to launch anything that would normally be considered safe 617 * once the user has gotten past the keyguard. 618 619 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 620 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 621 * instead; this allows you to seamlessly hide the keyguard as your application 622 * moves in and out of the foreground and does not require that any special 623 * permissions be requested. 624 */ 625 @Deprecated 626 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) exitKeyguardSecurely(final OnKeyguardExitResult callback)627 public void exitKeyguardSecurely(final OnKeyguardExitResult callback) { 628 try { 629 mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() { 630 public void onKeyguardExitResult(boolean success) throws RemoteException { 631 if (callback != null) { 632 callback.onKeyguardExitResult(success); 633 } 634 } 635 }); 636 } catch (RemoteException e) { 637 638 } 639 } 640 } 641