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