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.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresFeature;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.annotation.SystemService;
27 import android.annotation.TestApi;
28 import android.app.admin.DevicePolicyManager;
29 import android.app.admin.DevicePolicyManager.PasswordComplexity;
30 import android.app.admin.PasswordMetrics;
31 import android.app.trust.ITrustManager;
32 import android.compat.annotation.UnsupportedAppUsage;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.pm.PackageManager;
36 import android.content.pm.ResolveInfo;
37 import android.os.Binder;
38 import android.os.Build;
39 import android.os.IBinder;
40 import android.os.RemoteException;
41 import android.os.ServiceManager;
42 import android.os.ServiceManager.ServiceNotFoundException;
43 import android.provider.Settings;
44 import android.service.persistentdata.IPersistentDataBlockService;
45 import android.util.Log;
46 import android.view.IOnKeyguardExitResult;
47 import android.view.IWindowManager;
48 import android.view.WindowManager.LayoutParams;
49 import android.view.WindowManagerGlobal;
50 
51 import com.android.internal.policy.IKeyguardDismissCallback;
52 import com.android.internal.widget.LockPatternUtils;
53 import com.android.internal.widget.LockPatternView;
54 import com.android.internal.widget.LockscreenCredential;
55 import com.android.internal.widget.VerifyCredentialResponse;
56 
57 import java.nio.charset.Charset;
58 import java.util.Arrays;
59 import java.util.List;
60 
61 /**
62  * Class that can be used to lock and unlock the keyguard. The
63  * actual class to control the keyguard locking is
64  * {@link android.app.KeyguardManager.KeyguardLock}.
65  */
66 @SystemService(Context.KEYGUARD_SERVICE)
67 public class KeyguardManager {
68 
69     private static final String TAG = "KeyguardManager";
70 
71     private final Context mContext;
72     private final IWindowManager mWM;
73     private final IActivityManager mAm;
74     private final ITrustManager mTrustManager;
75     private final INotificationManager mNotificationManager;
76 
77     /**
78      * Intent used to prompt user for device credentials.
79      * @hide
80      */
81     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL =
82             "android.app.action.CONFIRM_DEVICE_CREDENTIAL";
83 
84     /**
85      * Intent used to prompt user for device credentials.
86      * @hide
87      */
88     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
89             "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
90 
91     /**
92      * Intent used to prompt user for factory reset credentials.
93      * @hide
94      */
95     public static final String ACTION_CONFIRM_FRP_CREDENTIAL =
96             "android.app.action.CONFIRM_FRP_CREDENTIAL";
97 
98     /**
99      * A CharSequence dialog title to show to the user when used with a
100      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
101      * @hide
102      */
103     public static final String EXTRA_TITLE = "android.app.extra.TITLE";
104 
105     /**
106      * A CharSequence description to show to the user when used with
107      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
108      * @hide
109      */
110     public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
111 
112     /**
113      * A CharSequence description to show to the user on the alternate button when used with
114      * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}.
115      * @hide
116      */
117     public static final String EXTRA_ALTERNATE_BUTTON_LABEL =
118             "android.app.extra.ALTERNATE_BUTTON_LABEL";
119 
120     /**
121      * Result code returned by the activity started by
122      * {@link #createConfirmFactoryResetCredentialIntent} indicating that the user clicked the
123      * alternate button.
124      *
125      * @hide
126      */
127     public static final int RESULT_ALTERNATE = 1;
128 
129     /**
130      *
131      * If this is set, check device policy for allowed biometrics when the user is authenticating.
132      * This should only be used in the context of managed profiles.
133      *
134      * @hide
135      */
136     public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm";
137 
138     /**
139      *
140      * Password lock type, see {@link #setLock}
141      *
142      * @hide
143      */
144     @SystemApi
145     public static final int PASSWORD = 0;
146 
147     /**
148      *
149      * Pin lock type, see {@link #setLock}
150      *
151      * @hide
152      */
153     @SystemApi
154     public static final int PIN = 1;
155 
156     /**
157      *
158      * Pattern lock type, see {@link #setLock}
159      *
160      * @hide
161      */
162     @SystemApi
163     public static final int PATTERN = 2;
164 
165     /**
166      * Available lock types
167      */
168     @IntDef({
169             PASSWORD,
170             PIN,
171             PATTERN
172     })
173     @interface LockTypes {}
174 
175     /**
176      * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
177      * if enrolled) for the current user of the device. The caller is expected to launch this
178      * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
179      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
180      *
181      * @return the intent for launching the activity or null if no password is required.
182      * @deprecated see BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)
183      */
184     @Deprecated
185     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description)186     public Intent createConfirmDeviceCredentialIntent(CharSequence title,
187             CharSequence description) {
188         if (!isDeviceSecure()) return null;
189         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
190         intent.putExtra(EXTRA_TITLE, title);
191         intent.putExtra(EXTRA_DESCRIPTION, description);
192 
193         // explicitly set the package for security
194         intent.setPackage(getSettingsPackageForIntent(intent));
195         return intent;
196     }
197 
198     /**
199      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
200      * for the given user. The caller is expected to launch this activity using
201      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
202      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
203      *
204      * @return the intent for launching the activity or null if no password is required.
205      *
206      * @hide
207      */
createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId)208     public Intent createConfirmDeviceCredentialIntent(
209             CharSequence title, CharSequence description, int userId) {
210         if (!isDeviceSecure(userId)) return null;
211         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
212         intent.putExtra(EXTRA_TITLE, title);
213         intent.putExtra(EXTRA_DESCRIPTION, description);
214         intent.putExtra(Intent.EXTRA_USER_ID, userId);
215 
216         // explicitly set the package for security
217         intent.setPackage(getSettingsPackageForIntent(intent));
218 
219         return intent;
220     }
221 
222     /**
223      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
224      * for the given user. The caller is expected to launch this activity using
225      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
226      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
227      *
228      * @param disallowBiometricsIfPolicyExists If true check if the Device Policy Manager has
229      * disabled biometrics on the device. If biometrics are disabled, fall back to PIN/pattern/pass.
230      *
231      * @return the intent for launching the activity or null if no password is required.
232      *
233      * @hide
234      */
createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId, boolean disallowBiometricsIfPolicyExists)235     public Intent createConfirmDeviceCredentialIntent(
236             CharSequence title, CharSequence description, int userId,
237             boolean disallowBiometricsIfPolicyExists) {
238         Intent intent = this.createConfirmDeviceCredentialIntent(title, description, userId);
239         intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
240                 disallowBiometricsIfPolicyExists);
241         return intent;
242     }
243 
244     /**
245      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
246      * for the previous owner of the device. The caller is expected to launch this activity using
247      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
248      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
249      *
250      * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon
251      *                             clicking this button, the activity returns
252      *                             {@link #RESULT_ALTERNATE}
253      *
254      * @return the intent for launching the activity or null if the previous owner of the device
255      *         did not set a credential.
256      * @throws UnsupportedOperationException if the device does not support factory reset
257      *                                       credentials
258      * @throws IllegalStateException if the device has already been provisioned
259      * @hide
260      */
261     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
262     @SystemApi
createConfirmFactoryResetCredentialIntent( CharSequence title, CharSequence description, CharSequence alternateButtonLabel)263     public Intent createConfirmFactoryResetCredentialIntent(
264             CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
265         if (!LockPatternUtils.frpCredentialEnabled(mContext)) {
266             Log.w(TAG, "Factory reset credentials not supported.");
267             throw new UnsupportedOperationException("not supported on this device");
268         }
269 
270         // Cannot verify credential if the device is provisioned
271         if (Settings.Global.getInt(mContext.getContentResolver(),
272                 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
273             Log.e(TAG, "Factory reset credential cannot be verified after provisioning.");
274             throw new IllegalStateException("must not be provisioned yet");
275         }
276 
277         // Make sure we have a credential
278         try {
279             IPersistentDataBlockService pdb = IPersistentDataBlockService.Stub.asInterface(
280                     ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE));
281             if (pdb == null) {
282                 Log.e(TAG, "No persistent data block service");
283                 throw new UnsupportedOperationException("not supported on this device");
284             }
285             // The following will throw an UnsupportedOperationException if the device does not
286             // support factory reset credentials (or something went wrong retrieving it).
287             if (!pdb.hasFrpCredentialHandle()) {
288                 Log.i(TAG, "The persistent data block does not have a factory reset credential.");
289                 return null;
290             }
291         } catch (RemoteException e) {
292             throw e.rethrowFromSystemServer();
293         }
294 
295         Intent intent = new Intent(ACTION_CONFIRM_FRP_CREDENTIAL);
296         intent.putExtra(EXTRA_TITLE, title);
297         intent.putExtra(EXTRA_DESCRIPTION, description);
298         intent.putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel);
299 
300         // explicitly set the package for security
301         intent.setPackage(getSettingsPackageForIntent(intent));
302 
303         return intent;
304     }
305 
306     /**
307      * Controls whether notifications can be shown atop a securely locked screen in their full
308      * private form (same as when the device is unlocked).
309      *
310      * <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration.
311      * The result is that private notifications are only shown if all sources allow it.
312      *
313      * @param allow secure notifications can be shown if {@code true},
314      * secure notifications cannot be shown if {@code false}
315      * @hide
316      */
317     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
318     @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
319     @SystemApi
setPrivateNotificationsAllowed(boolean allow)320     public void setPrivateNotificationsAllowed(boolean allow) {
321         try {
322             mNotificationManager.setPrivateNotificationsAllowed(allow);
323         } catch (RemoteException e) {
324             throw e.rethrowFromSystemServer();
325         }
326     }
327 
328     /**
329      * Returns whether notifications can be shown atop a securely locked screen in their full
330      * private form (same as when the device is unlocked).
331      *
332      * @return {@code true} if secure notifications can be shown, {@code false} otherwise.
333      * By default, private notifications are allowed.
334      * @hide
335      */
336     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
337     @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
338     @SystemApi
getPrivateNotificationsAllowed()339     public boolean getPrivateNotificationsAllowed() {
340         try {
341             return mNotificationManager.getPrivateNotificationsAllowed();
342         } catch (RemoteException e) {
343             throw e.rethrowFromSystemServer();
344         }
345     }
346 
getSettingsPackageForIntent(Intent intent)347     private String getSettingsPackageForIntent(Intent intent) {
348         List<ResolveInfo> resolveInfos = mContext.getPackageManager()
349                 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
350         for (int i = 0; i < resolveInfos.size(); i++) {
351             return resolveInfos.get(i).activityInfo.packageName;
352         }
353 
354         return "com.android.settings";
355     }
356 
357     /**
358      * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows
359      * you to disable / reenable the keyguard.
360      *
361      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
362      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
363      * instead; this allows you to seamlessly hide the keyguard as your application
364      * moves in and out of the foreground and does not require that any special
365      * permissions be requested.
366      */
367     @Deprecated
368     public class KeyguardLock {
369         private final IBinder mToken = new Binder();
370         private final String mTag;
371 
KeyguardLock(String tag)372         KeyguardLock(String tag) {
373             mTag = tag;
374         }
375 
376         /**
377          * Disable the keyguard from showing.  If the keyguard is currently
378          * showing, hide it.  The keyguard will be prevented from showing again
379          * until {@link #reenableKeyguard()} is called.
380          *
381          * A good place to call this is from {@link android.app.Activity#onResume()}
382          *
383          * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
384          * is enabled that requires a password.
385          *
386          * @see #reenableKeyguard()
387          */
388         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
disableKeyguard()389         public void disableKeyguard() {
390             try {
391                 mWM.disableKeyguard(mToken, mTag, mContext.getUserId());
392             } catch (RemoteException ex) {
393             }
394         }
395 
396         /**
397          * Reenable the keyguard.  The keyguard will reappear if the previous
398          * call to {@link #disableKeyguard()} caused it to be hidden.
399          *
400          * A good place to call this is from {@link android.app.Activity#onPause()}
401          *
402          * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
403          * is enabled that requires a password.
404          *
405          * @see #disableKeyguard()
406          */
407         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
reenableKeyguard()408         public void reenableKeyguard() {
409             try {
410                 mWM.reenableKeyguard(mToken, mContext.getUserId());
411             } catch (RemoteException ex) {
412             }
413         }
414     }
415 
416     /**
417      * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
418      * caller of result.
419      *
420      * @deprecated Use {@link KeyguardDismissCallback}
421      */
422     @Deprecated
423     public interface OnKeyguardExitResult {
424 
425         /**
426          * @param success True if the user was able to authenticate, false if
427          *   not.
428          */
onKeyguardExitResult(boolean success)429         void onKeyguardExitResult(boolean success);
430     }
431 
432     /**
433      * Callback passed to
434      * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardDismissCallback)}
435      * to notify caller of result.
436      */
437     public static abstract class KeyguardDismissCallback {
438 
439         /**
440          * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
441          * available, not showing or when the activity requesting the Keyguard dismissal isn't
442          * showing or isn't showing behind Keyguard.
443          */
onDismissError()444         public void onDismissError() { }
445 
446         /**
447          * Called when dismissing Keyguard has succeeded and the device is now unlocked.
448          */
onDismissSucceeded()449         public void onDismissSucceeded() { }
450 
451         /**
452          * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
453          * operation or the bouncer was hidden for some other reason.
454          */
onDismissCancelled()455         public void onDismissCancelled() { }
456     }
457 
KeyguardManager(Context context)458     KeyguardManager(Context context) throws ServiceNotFoundException {
459         mContext = context;
460         mWM = WindowManagerGlobal.getWindowManagerService();
461         mAm = ActivityManager.getService();
462         mTrustManager = ITrustManager.Stub.asInterface(
463                 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
464         mNotificationManager = INotificationManager.Stub.asInterface(
465                 ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
466     }
467 
468     /**
469      * Enables you to lock or unlock the keyguard. Get an instance of this class by
470      * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
471      * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}.
472      * @param tag A tag that informally identifies who you are (for debugging who
473      *   is disabling the keyguard).
474      *
475      * @return A {@link KeyguardLock} handle to use to disable and reenable the
476      *   keyguard.
477      *
478      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
479      *   and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
480      *   instead; this allows you to seamlessly hide the keyguard as your application
481      *   moves in and out of the foreground and does not require that any special
482      *   permissions be requested.
483      */
484     @Deprecated
newKeyguardLock(String tag)485     public KeyguardLock newKeyguardLock(String tag) {
486         return new KeyguardLock(tag);
487     }
488 
489     /**
490      * Return whether the keyguard is currently locked.
491      *
492      * @return true if keyguard is locked.
493      */
isKeyguardLocked()494     public boolean isKeyguardLocked() {
495         try {
496             return mWM.isKeyguardLocked();
497         } catch (RemoteException ex) {
498             return false;
499         }
500     }
501 
502     /**
503      * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card
504      * is currently locked.
505      *
506      * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
507      *
508      * @return true if a PIN, pattern or password is set or a SIM card is locked.
509      */
isKeyguardSecure()510     public boolean isKeyguardSecure() {
511         try {
512             return mWM.isKeyguardSecure(mContext.getUserId());
513         } catch (RemoteException ex) {
514             return false;
515         }
516     }
517 
518     /**
519      * If keyguard screen is showing or in restricted key input mode (i.e. in
520      * keyguard password emergency screen). When in such mode, certain keys,
521      * such as the Home key and the right soft keys, don't work.
522      *
523      * @return true if in keyguard restricted input mode.
524      * @deprecated Use {@link #isKeyguardLocked()} instead.
525      */
inKeyguardRestrictedInputMode()526     public boolean inKeyguardRestrictedInputMode() {
527         return isKeyguardLocked();
528     }
529 
530     /**
531      * Returns whether the device is currently locked and requires a PIN, pattern or
532      * password to unlock.
533      *
534      * @return true if unlocking the device currently requires a PIN, pattern or
535      * password.
536      */
isDeviceLocked()537     public boolean isDeviceLocked() {
538         return isDeviceLocked(mContext.getUserId());
539     }
540 
541     /**
542      * Per-user version of {@link #isDeviceLocked()}.
543      *
544      * @hide
545      */
546     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isDeviceLocked(int userId)547     public boolean isDeviceLocked(int userId) {
548         try {
549             return mTrustManager.isDeviceLocked(userId);
550         } catch (RemoteException e) {
551             return false;
552         }
553     }
554 
555     /**
556      * Returns whether the device is secured with a PIN, pattern or
557      * password.
558      *
559      * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
560      *
561      * @return true if a PIN, pattern or password was set.
562      */
isDeviceSecure()563     public boolean isDeviceSecure() {
564         return isDeviceSecure(mContext.getUserId());
565     }
566 
567     /**
568      * Per-user version of {@link #isDeviceSecure()}.
569      *
570      * @hide
571      */
572     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isDeviceSecure(int userId)573     public boolean isDeviceSecure(int userId) {
574         try {
575             return mTrustManager.isDeviceSecure(userId);
576         } catch (RemoteException e) {
577             return false;
578         }
579     }
580 
581     /**
582      * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
583      * be dismissed.
584      * <p>
585      * If the Keyguard is not secure or the device is currently in a trusted state, calling this
586      * method will immediately dismiss the Keyguard without any user interaction.
587      * <p>
588      * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
589      * UI so the user can enter their credentials.
590      * <p>
591      * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true,
592      * the screen will turn on when the keyguard is dismissed.
593      *
594      * @param activity The activity requesting the dismissal. The activity must be either visible
595      *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
596      *                 which it would be visible if Keyguard would not be hiding it. If that's not
597      *                 the case, the request will fail immediately and
598      *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
599      * @param callback The callback to be called if the request to dismiss Keyguard was successful
600      *                 or {@code null} if the caller isn't interested in knowing the result. The
601      *                 callback will not be invoked if the activity was destroyed before the
602      *                 callback was received.
603      */
requestDismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback)604     public void requestDismissKeyguard(@NonNull Activity activity,
605             @Nullable KeyguardDismissCallback callback) {
606         requestDismissKeyguard(activity, null /* message */, callback);
607     }
608 
609     /**
610      * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
611      * be dismissed.
612      * <p>
613      * If the Keyguard is not secure or the device is currently in a trusted state, calling this
614      * method will immediately dismiss the Keyguard without any user interaction.
615      * <p>
616      * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
617      * UI so the user can enter their credentials.
618      * <p>
619      * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true,
620      * the screen will turn on when the keyguard is dismissed.
621      *
622      * @param activity The activity requesting the dismissal. The activity must be either visible
623      *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
624      *                 which it would be visible if Keyguard would not be hiding it. If that's not
625      *                 the case, the request will fail immediately and
626      *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
627      * @param message  A message that will be shown in the keyguard explaining why the user
628      *                 would want to dismiss it.
629      * @param callback The callback to be called if the request to dismiss Keyguard was successful
630      *                 or {@code null} if the caller isn't interested in knowing the result. The
631      *                 callback will not be invoked if the activity was destroyed before the
632      *                 callback was received.
633      * @hide
634      */
635     @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE)
636     @SystemApi
requestDismissKeyguard(@onNull Activity activity, @Nullable CharSequence message, @Nullable KeyguardDismissCallback callback)637     public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message,
638             @Nullable KeyguardDismissCallback callback) {
639         ActivityClient.getInstance().dismissKeyguard(
640                 activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
641             @Override
642             public void onDismissError() throws RemoteException {
643                 if (callback != null && !activity.isDestroyed()) {
644                     activity.mHandler.post(callback::onDismissError);
645                 }
646             }
647 
648             @Override
649             public void onDismissSucceeded() throws RemoteException {
650                 if (callback != null && !activity.isDestroyed()) {
651                     activity.mHandler.post(callback::onDismissSucceeded);
652                 }
653             }
654 
655             @Override
656             public void onDismissCancelled() throws RemoteException {
657                 if (callback != null && !activity.isDestroyed()) {
658                     activity.mHandler.post(callback::onDismissCancelled);
659                 }
660             }
661         }, message);
662     }
663 
664     /**
665      * Exit the keyguard securely.  The use case for this api is that, after
666      * disabling the keyguard, your app, which was granted permission to
667      * disable the keyguard and show a limited amount of information deemed
668      * safe without the user getting past the keyguard, needs to navigate to
669      * something that is not safe to view without getting past the keyguard.
670      *
671      * This will, if the keyguard is secure, bring up the unlock screen of
672      * the keyguard.
673      *
674      * @param callback Lets you know whether the operation was successful and
675      *   it is safe to launch anything that would normally be considered safe
676      *   once the user has gotten past the keyguard.
677 
678      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
679      *   and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
680      *   instead; this allows you to seamlessly hide the keyguard as your application
681      *   moves in and out of the foreground and does not require that any special
682      *   permissions be requested.
683      */
684     @Deprecated
685     @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
exitKeyguardSecurely(final OnKeyguardExitResult callback)686     public void exitKeyguardSecurely(final OnKeyguardExitResult callback) {
687         try {
688             mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() {
689                 public void onKeyguardExitResult(boolean success) throws RemoteException {
690                     if (callback != null) {
691                         callback.onKeyguardExitResult(success);
692                     }
693                 }
694             });
695         } catch (RemoteException e) {
696 
697         }
698     }
699 
checkInitialLockMethodUsage()700     private boolean checkInitialLockMethodUsage() {
701         if (!hasPermission(Manifest.permission.SET_INITIAL_LOCK)) {
702             throw new SecurityException("Requires SET_INITIAL_LOCK permission.");
703         }
704         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
705     }
706 
hasPermission(String permission)707     private boolean hasPermission(String permission) {
708         return PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
709                 permission);
710     }
711 
712     /**
713     * Determine if a given password is valid based off its lock type and expected complexity level.
714     *
715     * @param lockType - type of lock as specified in {@link LockTypes}
716     * @param password - password to validate; this has the same encoding
717     *        as the output of String#getBytes
718     * @param complexity - complexity level imposed by the requester
719     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
720     * @return true if the password is valid, false otherwise
721     * @hide
722     */
723     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
724     @SystemApi
isValidLockPasswordComplexity(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)725     public boolean isValidLockPasswordComplexity(@LockTypes int lockType, @NonNull byte[] password,
726             @PasswordComplexity int complexity) {
727         if (!checkInitialLockMethodUsage()) {
728             return false;
729         }
730         complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
731         // TODO: b/131755827 add devicePolicyManager support for Auto
732         DevicePolicyManager devicePolicyManager =
733                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
734         PasswordMetrics adminMetrics =
735                 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
736         // Check if the password fits the mold of a pin or pattern.
737         boolean isPinOrPattern = lockType != PASSWORD;
738 
739         return PasswordMetrics.validatePassword(
740                 adminMetrics, complexity, isPinOrPattern, password).size() == 0;
741     }
742 
743     /**
744     * Determine the minimum allowable length for a lock type for a given complexity level.
745     *
746     * @param isPin - whether this is a PIN-type password (only digits)
747     * @param complexity - complexity level imposed by the requester
748     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
749     * @return minimum allowable password length
750     * @hide
751     */
752     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
753     @SystemApi
getMinLockLength(boolean isPin, @PasswordComplexity int complexity)754     public int getMinLockLength(boolean isPin, @PasswordComplexity int complexity) {
755         if (!checkInitialLockMethodUsage()) {
756             return -1;
757         }
758         complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
759         // TODO: b/131755827 add devicePolicyManager support for Auto
760         DevicePolicyManager devicePolicyManager =
761                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
762         PasswordMetrics adminMetrics =
763                 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
764         PasswordMetrics minMetrics =
765                 PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity);
766         return minMetrics.length;
767     }
768 
769     /**
770     * Set the lockscreen password after validating against its expected complexity level.
771     *
772     * @param lockType - type of lock as specified in {@link LockTypes}
773     * @param password - password to validate; this has the same encoding
774     *        as the output of String#getBytes
775     * @param complexity - complexity level imposed by the requester
776     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
777     * @return true if the lock is successfully set, false otherwise
778     * @hide
779     */
780     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
781     @SystemApi
setLock(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)782     public boolean setLock(@LockTypes int lockType, @NonNull byte[] password,
783             @PasswordComplexity int complexity) {
784         if (!checkInitialLockMethodUsage()) {
785             return false;
786         }
787 
788         LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
789         int userId = mContext.getUserId();
790         if (isDeviceSecure(userId)) {
791             Log.e(TAG, "Password already set, rejecting call to setLock");
792             return false;
793         }
794         if (!isValidLockPasswordComplexity(lockType, password, complexity)) {
795             Log.e(TAG, "Password is not valid, rejecting call to setLock");
796             return false;
797         }
798         boolean success;
799         try {
800             LockscreenCredential credential = createLockscreenCredential(
801                     lockType, password);
802             success = lockPatternUtils.setLockCredential(
803                     credential,
804                     /* savedPassword= */ LockscreenCredential.createNone(),
805                     userId);
806         } catch (Exception e) {
807             Log.e(TAG, "Save lock exception", e);
808             success = false;
809         } finally {
810             Arrays.fill(password, (byte) 0);
811         }
812         return success;
813     }
814 
815     /**
816      * Set the lockscreen password to {@code newPassword} after validating the current password
817      * against {@code currentPassword}.
818      * <p>If no password is currently set, {@code currentPassword} should be set to {@code null}.
819      * <p>To clear the current password, {@code newPassword} should be set to {@code null}.
820      *
821      * @return {@code true} if password successfully set.
822      *
823      * @throws IllegalArgumentException if {@code newLockType} or {@code currentLockType}
824      * is invalid.
825      *
826      * @hide
827      */
828     @TestApi
829     @RequiresPermission(anyOf = {
830             Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS,
831             Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE
832     })
setLock(@ockTypes int newLockType, @Nullable byte[] newPassword, @LockTypes int currentLockType, @Nullable byte[] currentPassword)833     public boolean setLock(@LockTypes int newLockType, @Nullable byte[] newPassword,
834             @LockTypes int currentLockType, @Nullable byte[] currentPassword) {
835         final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
836         final int userId = mContext.getUserId();
837         LockscreenCredential currentCredential = createLockscreenCredential(
838                 currentLockType, currentPassword);
839         LockscreenCredential newCredential = createLockscreenCredential(
840                 newLockType, newPassword);
841         return lockPatternUtils.setLockCredential(newCredential, currentCredential, userId);
842     }
843 
844     /**
845      * Verifies the current lock credentials against {@code password}.
846      * <p>To check if no password is set, {@code password} should be set to {@code null}.
847      *
848      * @return {@code true} if credentials match
849      *
850      * @throws IllegalArgumentException if {@code lockType} is invalid.
851      *
852      * @hide
853      */
854     @TestApi
855     @RequiresPermission(anyOf = {
856             Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS,
857             Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE
858     })
checkLock(@ockTypes int lockType, @Nullable byte[] password)859     public boolean checkLock(@LockTypes int lockType, @Nullable byte[] password) {
860         final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
861         final LockscreenCredential credential = createLockscreenCredential(
862                 lockType, password);
863         final VerifyCredentialResponse response = lockPatternUtils.verifyCredential(
864                 credential, mContext.getUserId(), /* flags= */ 0);
865         if (response == null) {
866             return false;
867         }
868         return response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK;
869     }
870 
createLockscreenCredential( @ockTypes int lockType, @Nullable byte[] password)871     private LockscreenCredential createLockscreenCredential(
872             @LockTypes int lockType, @Nullable byte[] password) {
873         if (password == null) {
874             return LockscreenCredential.createNone();
875         }
876         switch (lockType) {
877             case PASSWORD:
878                 CharSequence passwordStr = new String(password, Charset.forName("UTF-8"));
879                 return LockscreenCredential.createPassword(passwordStr);
880             case PIN:
881                 CharSequence pinStr = new String(password);
882                 return LockscreenCredential.createPin(pinStr);
883             case PATTERN:
884                 List<LockPatternView.Cell> pattern =
885                         LockPatternUtils.byteArrayToPattern(password);
886                 return LockscreenCredential.createPattern(pattern);
887             default:
888                 throw new IllegalArgumentException("Unknown lock type " + lockType);
889         }
890     }
891 }
892