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.RequiresPermission;
     23 import android.annotation.SystemService;
     24 import android.app.trust.ITrustManager;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.pm.PackageManager;
     28 import android.content.pm.ResolveInfo;
     29 import android.os.Binder;
     30 import android.os.Handler;
     31 import android.os.IBinder;
     32 import android.os.Looper;
     33 import android.os.RemoteException;
     34 import android.os.ServiceManager;
     35 import android.os.ServiceManager.ServiceNotFoundException;
     36 import android.os.UserHandle;
     37 import android.util.Log;
     38 import android.view.IOnKeyguardExitResult;
     39 import android.view.IWindowManager;
     40 import android.view.WindowManager.LayoutParams;
     41 import android.view.WindowManagerGlobal;
     42 
     43 import com.android.internal.policy.IKeyguardDismissCallback;
     44 
     45 import java.util.List;
     46 
     47 /**
     48  * Class that can be used to lock and unlock the keyboard. The
     49  * actual class to control the keyboard locking is
     50  * {@link android.app.KeyguardManager.KeyguardLock}.
     51  */
     52 @SystemService(Context.KEYGUARD_SERVICE)
     53 public class KeyguardManager {
     54 
     55     private static final String TAG = "KeyguardManager";
     56 
     57     private final Context mContext;
     58     private final IWindowManager mWM;
     59     private final IActivityManager mAm;
     60     private final ITrustManager mTrustManager;
     61 
     62     /**
     63      * Intent used to prompt user for device credentials.
     64      * @hide
     65      */
     66     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL =
     67             "android.app.action.CONFIRM_DEVICE_CREDENTIAL";
     68 
     69     /**
     70      * Intent used to prompt user for device credentials.
     71      * @hide
     72      */
     73     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
     74             "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
     75 
     76     /**
     77      * A CharSequence dialog title to show to the user when used with a
     78      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
     79      * @hide
     80      */
     81     public static final String EXTRA_TITLE = "android.app.extra.TITLE";
     82 
     83     /**
     84      * A CharSequence description to show to the user when used with
     85      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
     86      * @hide
     87      */
     88     public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
     89 
     90     /**
     91      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
     92      * for the current user of the device. The caller is expected to launch this activity using
     93      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
     94      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
     95      *
     96      * @return the intent for launching the activity or null if no password is required.
     97      **/
     98     public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
     99         if (!isDeviceSecure()) return null;
    100         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
    101         intent.putExtra(EXTRA_TITLE, title);
    102         intent.putExtra(EXTRA_DESCRIPTION, description);
    103 
    104         // explicitly set the package for security
    105         intent.setPackage(getSettingsPackageForIntent(intent));
    106         return intent;
    107     }
    108 
    109     /**
    110      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
    111      * for the given user. The caller is expected to launch this activity using
    112      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
    113      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
    114      *
    115      * @return the intent for launching the activity or null if no password is required.
    116      *
    117      * @hide
    118      */
    119     public Intent createConfirmDeviceCredentialIntent(
    120             CharSequence title, CharSequence description, int userId) {
    121         if (!isDeviceSecure(userId)) return null;
    122         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
    123         intent.putExtra(EXTRA_TITLE, title);
    124         intent.putExtra(EXTRA_DESCRIPTION, description);
    125         intent.putExtra(Intent.EXTRA_USER_ID, userId);
    126 
    127         // explicitly set the package for security
    128         intent.setPackage(getSettingsPackageForIntent(intent));
    129 
    130         return intent;
    131     }
    132 
    133     private String getSettingsPackageForIntent(Intent intent) {
    134         List<ResolveInfo> resolveInfos = mContext.getPackageManager()
    135                 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
    136         for (int i = 0; i < resolveInfos.size(); i++) {
    137             return resolveInfos.get(i).activityInfo.packageName;
    138         }
    139 
    140         return "com.android.settings";
    141     }
    142 
    143     /**
    144      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
    145      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
    146      * instead; this allows you to seamlessly hide the keyguard as your application
    147      * moves in and out of the foreground and does not require that any special
    148      * permissions be requested.
    149      *
    150      * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows
    151      * you to disable / reenable the keyguard.
    152      */
    153     @Deprecated
    154     public class KeyguardLock {
    155         private final IBinder mToken = new Binder();
    156         private final String mTag;
    157 
    158         KeyguardLock(String tag) {
    159             mTag = tag;
    160         }
    161 
    162         /**
    163          * Disable the keyguard from showing.  If the keyguard is currently
    164          * showing, hide it.  The keyguard will be prevented from showing again
    165          * until {@link #reenableKeyguard()} is called.
    166          *
    167          * A good place to call this is from {@link android.app.Activity#onResume()}
    168          *
    169          * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
    170          * is enabled that requires a password.
    171          *
    172          * @see #reenableKeyguard()
    173          */
    174         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
    175         public void disableKeyguard() {
    176             try {
    177                 mWM.disableKeyguard(mToken, mTag);
    178             } catch (RemoteException ex) {
    179             }
    180         }
    181 
    182         /**
    183          * Reenable the keyguard.  The keyguard will reappear if the previous
    184          * call to {@link #disableKeyguard()} caused it to be hidden.
    185          *
    186          * A good place to call this is from {@link android.app.Activity#onPause()}
    187          *
    188          * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
    189          * is enabled that requires a password.
    190          *
    191          * @see #disableKeyguard()
    192          */
    193         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
    194         public void reenableKeyguard() {
    195             try {
    196                 mWM.reenableKeyguard(mToken);
    197             } catch (RemoteException ex) {
    198             }
    199         }
    200     }
    201 
    202     /**
    203      * @deprecated Use {@link KeyguardDismissCallback}
    204      * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
    205      * caller of result.
    206      */
    207     @Deprecated
    208     public interface OnKeyguardExitResult {
    209 
    210         /**
    211          * @param success True if the user was able to authenticate, false if
    212          *   not.
    213          */
    214         void onKeyguardExitResult(boolean success);
    215     }
    216 
    217     /**
    218      * Callback passed to {@link KeyguardManager#dismissKeyguard} to notify caller of result.
    219      */
    220     public static abstract class KeyguardDismissCallback {
    221 
    222         /**
    223          * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
    224          * available, not showing or when the activity requesting the Keyguard dismissal isn't
    225          * showing or isn't showing behind Keyguard.
    226          */
    227         public void onDismissError() { }
    228 
    229         /**
    230          * Called when dismissing Keyguard has succeeded and the device is now unlocked.
    231          */
    232         public void onDismissSucceeded() { }
    233 
    234         /**
    235          * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
    236          * operation or the bouncer was hidden for some other reason.
    237          */
    238         public void onDismissCancelled() { }
    239     }
    240 
    241     KeyguardManager(Context context) throws ServiceNotFoundException {
    242         mContext = context;
    243         mWM = WindowManagerGlobal.getWindowManagerService();
    244         mAm = ActivityManager.getService();
    245         mTrustManager = ITrustManager.Stub.asInterface(
    246                 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
    247     }
    248 
    249     /**
    250      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
    251      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
    252      * instead; this allows you to seamlessly hide the keyguard as your application
    253      * moves in and out of the foreground and does not require that any special
    254      * permissions be requested.
    255      *
    256      * Enables you to lock or unlock the keyboard. Get an instance of this class by
    257      * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
    258      * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}.
    259      * @param tag A tag that informally identifies who you are (for debugging who
    260      *   is disabling he keyguard).
    261      *
    262      * @return A {@link KeyguardLock} handle to use to disable and reenable the
    263      *   keyguard.
    264      */
    265     @Deprecated
    266     public KeyguardLock newKeyguardLock(String tag) {
    267         return new KeyguardLock(tag);
    268     }
    269 
    270     /**
    271      * Return whether the keyguard is currently locked.
    272      *
    273      * @return true if keyguard is locked.
    274      */
    275     public boolean isKeyguardLocked() {
    276         try {
    277             return mWM.isKeyguardLocked();
    278         } catch (RemoteException ex) {
    279             return false;
    280         }
    281     }
    282 
    283     /**
    284      * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card
    285      * is currently locked.
    286      *
    287      * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
    288      *
    289      * @return true if a PIN, pattern or password is set or a SIM card is locked.
    290      */
    291     public boolean isKeyguardSecure() {
    292         try {
    293             return mWM.isKeyguardSecure();
    294         } catch (RemoteException ex) {
    295             return false;
    296         }
    297     }
    298 
    299     /**
    300      * If keyguard screen is showing or in restricted key input mode (i.e. in
    301      * keyguard password emergency screen). When in such mode, certain keys,
    302      * such as the Home key and the right soft keys, don't work.
    303      *
    304      * @return true if in keyguard restricted input mode.
    305      *
    306      * @see android.view.WindowManagerPolicy#inKeyguardRestrictedKeyInputMode
    307      */
    308     public boolean inKeyguardRestrictedInputMode() {
    309         try {
    310             return mWM.inKeyguardRestrictedInputMode();
    311         } catch (RemoteException ex) {
    312             return false;
    313         }
    314     }
    315 
    316     /**
    317      * Returns whether the device is currently locked and requires a PIN, pattern or
    318      * password to unlock.
    319      *
    320      * @return true if unlocking the device currently requires a PIN, pattern or
    321      * password.
    322      */
    323     public boolean isDeviceLocked() {
    324         return isDeviceLocked(UserHandle.myUserId());
    325     }
    326 
    327     /**
    328      * Per-user version of {@link #isDeviceLocked()}.
    329      *
    330      * @hide
    331      */
    332     public boolean isDeviceLocked(int userId) {
    333         try {
    334             return mTrustManager.isDeviceLocked(userId);
    335         } catch (RemoteException e) {
    336             return false;
    337         }
    338     }
    339 
    340     /**
    341      * Returns whether the device is secured with a PIN, pattern or
    342      * password.
    343      *
    344      * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
    345      *
    346      * @return true if a PIN, pattern or password was set.
    347      */
    348     public boolean isDeviceSecure() {
    349         return isDeviceSecure(UserHandle.myUserId());
    350     }
    351 
    352     /**
    353      * Per-user version of {@link #isDeviceSecure()}.
    354      *
    355      * @hide
    356      */
    357     public boolean isDeviceSecure(int userId) {
    358         try {
    359             return mTrustManager.isDeviceSecure(userId);
    360         } catch (RemoteException e) {
    361             return false;
    362         }
    363     }
    364 
    365     /** @removed */
    366     @Deprecated
    367     public void dismissKeyguard(@NonNull Activity activity,
    368             @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
    369         requestDismissKeyguard(activity, callback);
    370     }
    371 
    372     /**
    373      * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
    374      * be dismissed.
    375      * <p>
    376      * If the Keyguard is not secure or the device is currently in a trusted state, calling this
    377      * method will immediately dismiss the Keyguard without any user interaction.
    378      * <p>
    379      * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
    380      * UI so the user can enter their credentials.
    381      *
    382      * @param activity The activity requesting the dismissal. The activity must be either visible
    383      *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
    384      *                 which it would be visible if Keyguard would not be hiding it. If that's not
    385      *                 the case, the request will fail immediately and
    386      *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
    387      * @param callback The callback to be called if the request to dismiss Keyguard was successful
    388      *                 or {@code null} if the caller isn't interested in knowing the result. The
    389      *                 callback will not be invoked if the activity was destroyed before the
    390      *                 callback was received.
    391      */
    392     public void requestDismissKeyguard(@NonNull Activity activity,
    393             @Nullable KeyguardDismissCallback callback) {
    394         try {
    395             mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
    396                 @Override
    397                 public void onDismissError() throws RemoteException {
    398                     if (callback != null && !activity.isDestroyed()) {
    399                         activity.mHandler.post(callback::onDismissError);
    400                     }
    401                 }
    402 
    403                 @Override
    404                 public void onDismissSucceeded() throws RemoteException {
    405                     if (callback != null && !activity.isDestroyed()) {
    406                         activity.mHandler.post(callback::onDismissSucceeded);
    407                     }
    408                 }
    409 
    410                 @Override
    411                 public void onDismissCancelled() throws RemoteException {
    412                     if (callback != null && !activity.isDestroyed()) {
    413                         activity.mHandler.post(callback::onDismissCancelled);
    414                     }
    415                 }
    416             });
    417         } catch (RemoteException e) {
    418             Log.i(TAG, "Failed to dismiss keyguard: " + e);
    419         }
    420     }
    421 
    422     /**
    423      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
    424      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
    425      * instead; this allows you to seamlessly hide the keyguard as your application
    426      * moves in and out of the foreground and does not require that any special
    427      * permissions be requested.
    428      *
    429      * Exit the keyguard securely.  The use case for this api is that, after
    430      * disabling the keyguard, your app, which was granted permission to
    431      * disable the keyguard and show a limited amount of information deemed
    432      * safe without the user getting past the keyguard, needs to navigate to
    433      * something that is not safe to view without getting past the keyguard.
    434      *
    435      * This will, if the keyguard is secure, bring up the unlock screen of
    436      * the keyguard.
    437      *
    438      * @param callback Let's you know whether the operation was succesful and
    439      *   it is safe to launch anything that would normally be considered safe
    440      *   once the user has gotten past the keyguard.
    441      */
    442     @Deprecated
    443     @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
    444     public void exitKeyguardSecurely(final OnKeyguardExitResult callback) {
    445         try {
    446             mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() {
    447                 public void onKeyguardExitResult(boolean success) throws RemoteException {
    448                     if (callback != null) {
    449                         callback.onKeyguardExitResult(success);
    450                     }
    451                 }
    452             });
    453         } catch (RemoteException e) {
    454 
    455         }
    456     }
    457 }
    458