• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.UnsupportedAppUsage;
27 import android.app.trust.ITrustManager;
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