Home | History | Annotate | Download | only in app
      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)
    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      */
    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
    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
    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
    269     public boolean getPrivateNotificationsAllowed() {
    270         try {
    271             return mNotificationManager.getPrivateNotificationsAllowed();
    272         } catch (RemoteException e) {
    273             throw e.rethrowFromSystemServer();
    274         }
    275     }
    276 
    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 
    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)
    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)
    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          */
    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          */
    374         public void onDismissError() { }
    375 
    376         /**
    377          * Called when dismissing Keyguard has succeeded and the device is now unlocked.
    378          */
    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          */
    385         public void onDismissCancelled() { }
    386     }
    387 
    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
    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      */
    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      */
    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      */
    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      */
    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)
    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      */
    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
    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
    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      */
    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
    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)
    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