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.CallbackExecutor;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresFeature;
25 import android.annotation.RequiresPermission;
26 import android.annotation.SystemApi;
27 import android.annotation.SystemService;
28 import android.annotation.TestApi;
29 import android.annotation.UserIdInt;
30 import android.app.admin.DevicePolicyManager;
31 import android.app.admin.DevicePolicyManager.PasswordComplexity;
32 import android.app.admin.PasswordMetrics;
33 import android.app.trust.ITrustManager;
34 import android.compat.annotation.UnsupportedAppUsage;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.os.Binder;
41 import android.os.Build;
42 import android.os.IBinder;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.ServiceManager.ServiceNotFoundException;
46 import android.os.UserHandle;
47 import android.provider.Settings;
48 import android.service.persistentdata.IPersistentDataBlockService;
49 import android.util.ArrayMap;
50 import android.util.Log;
51 import android.view.IOnKeyguardExitResult;
52 import android.view.IWindowManager;
53 import android.view.WindowManagerGlobal;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.policy.IKeyguardDismissCallback;
57 import com.android.internal.policy.IKeyguardLockedStateListener;
58 import com.android.internal.util.Preconditions;
59 import com.android.internal.widget.IWeakEscrowTokenActivatedListener;
60 import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
61 import com.android.internal.widget.LockPatternUtils;
62 import com.android.internal.widget.LockPatternView;
63 import com.android.internal.widget.LockscreenCredential;
64 import com.android.internal.widget.PasswordValidationError;
65 import com.android.internal.widget.VerifyCredentialResponse;
66 
67 import java.lang.annotation.Retention;
68 import java.lang.annotation.RetentionPolicy;
69 import java.nio.charset.Charset;
70 import java.util.Arrays;
71 import java.util.List;
72 import java.util.Objects;
73 import java.util.concurrent.Executor;
74 
75 /**
76  * Class to manage and query the state of the lock screen (also known as Keyguard).
77  */
78 @SystemService(Context.KEYGUARD_SERVICE)
79 public class KeyguardManager {
80 
81     private static final String TAG = "KeyguardManager";
82 
83     private final Context mContext;
84     private final LockPatternUtils mLockPatternUtils;
85     private final IWindowManager mWM;
86     private final IActivityManager mAm;
87     private final ITrustManager mTrustManager;
88     private final INotificationManager mNotificationManager;
89     private final ArrayMap<WeakEscrowTokenRemovedListener, IWeakEscrowTokenRemovedListener>
90             mListeners = new ArrayMap<>();
91 
92     /**
93      * Intent used to prompt user for device credentials.
94      * @hide
95      */
96     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL =
97             "android.app.action.CONFIRM_DEVICE_CREDENTIAL";
98 
99     /**
100      * Intent used to prompt user for device credentials.
101      * @hide
102      */
103     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
104             "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
105 
106     /**
107      * Intent used to prompt user for factory reset credentials.
108      * @hide
109      */
110     public static final String ACTION_CONFIRM_FRP_CREDENTIAL =
111             "android.app.action.CONFIRM_FRP_CREDENTIAL";
112 
113     /**
114      * Intent used to prompt user to to validate the credentials of a remote device.
115      * @hide
116      */
117     public static final String ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL =
118             "android.app.action.CONFIRM_REMOTE_DEVICE_CREDENTIAL";
119 
120     /**
121      * Intent used to prompt user for device credential for entering repair
122      * mode. If the credential is verified successfully, then the information
123      * needed to verify the credential again will be written to a location that
124      * is available to repair mode. This makes it possible for repair mode to
125      * require that the same credential be provided to exit repair mode.
126      * @hide
127      */
128     public static final String ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL =
129             "android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL";
130 
131     /**
132      * Intent used to prompt user for device credential that is written by
133      * {@link #ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL} for exiting
134      * repair mode.
135      * @hide
136      */
137     public static final String ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL =
138             "android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL";
139 
140     /**
141      * A CharSequence dialog title to show to the user when used with a
142      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
143      * @hide
144      */
145     public static final String EXTRA_TITLE = "android.app.extra.TITLE";
146 
147     /**
148      * A CharSequence description to show to the user when used with
149      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
150      * @hide
151      */
152     public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
153 
154     /**
155      * A CharSequence description to show to the user on the alternate button when used with
156      * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}.
157      * @hide
158      */
159     public static final String EXTRA_ALTERNATE_BUTTON_LABEL =
160             "android.app.extra.ALTERNATE_BUTTON_LABEL";
161 
162     /**
163      * A CharSequence label for the checkbox when used with
164      * {@link #ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL}
165      * @hide
166      */
167     public static final String EXTRA_CHECKBOX_LABEL = "android.app.extra.CHECKBOX_LABEL";
168 
169     /**
170      * A {@link RemoteLockscreenValidationSession} extra to be sent along with
171      * {@link #ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL} containing the data needed to prompt for
172      * a remote device's lock screen.
173      * @hide
174      */
175     public static final String EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION =
176             "android.app.extra.REMOTE_LOCKSCREEN_VALIDATION_SESSION";
177 
178     /**
179      * A boolean indicating that credential confirmation activity should be a task overlay.
180      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER}.
181      * @hide
182      */
183     public static final String EXTRA_FORCE_TASK_OVERLAY =
184             "android.app.KeyguardManager.FORCE_TASK_OVERLAY";
185 
186     /**
187      * Result code returned by the activity started by
188      * {@link #createConfirmFactoryResetCredentialIntent} or
189      * {@link #createConfirmDeviceCredentialForRemoteValidationIntent}
190      * indicating that the user clicked the alternate button.
191      *
192      * @hide
193      */
194     public static final int RESULT_ALTERNATE = 1;
195 
196     /**
197      *
198      * If this is set, check device policy for allowed biometrics when the user is authenticating.
199      * This should only be used in the context of managed profiles.
200      *
201      * @hide
202      */
203     public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm";
204 
205     /**
206      *
207      * Password lock type, see {@link #setLock}
208      *
209      * @hide
210      */
211     @SystemApi
212     public static final int PASSWORD = 0;
213 
214     /**
215      *
216      * Pin lock type, see {@link #setLock}
217      *
218      * @hide
219      */
220     @SystemApi
221     public static final int PIN = 1;
222 
223     /**
224      *
225      * Pattern lock type, see {@link #setLock}
226      *
227      * @hide
228      */
229     @SystemApi
230     public static final int PATTERN = 2;
231 
232     /**
233      * Available lock types
234      */
235     @IntDef({
236             PASSWORD,
237             PIN,
238             PATTERN
239     })
240     @Retention(RetentionPolicy.SOURCE)
241     @interface LockTypes {}
242 
243     private final IKeyguardLockedStateListener mIKeyguardLockedStateListener =
244             new IKeyguardLockedStateListener.Stub() {
245                 @Override
246                 public void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
247                     mKeyguardLockedStateListeners.forEach((listener, executor) -> {
248                         executor.execute(
249                                 () -> listener.onKeyguardLockedStateChanged(isKeyguardLocked));
250                     });
251                 }
252             };
253     private final ArrayMap<KeyguardLockedStateListener, Executor>
254             mKeyguardLockedStateListeners = new ArrayMap<>();
255 
256     /**
257      * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
258      * if enrolled) for the current user of the device. The caller is expected to launch this
259      * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
260      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
261      *
262      * @return the intent for launching the activity or null if no password is required.
263      *
264      * @deprecated see {@link
265      *   android.hardware.biometrics.BiometricPrompt.Builder#setAllowedAuthenticators(int)}
266      */
267     @Deprecated
268     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description)269     public Intent createConfirmDeviceCredentialIntent(CharSequence title,
270             CharSequence description) {
271         if (!isDeviceSecure()) return null;
272         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
273         intent.putExtra(EXTRA_TITLE, title);
274         intent.putExtra(EXTRA_DESCRIPTION, description);
275 
276         // explicitly set the package for security
277         intent.setPackage(getSettingsPackageForIntent(intent));
278         return intent;
279     }
280 
281     /**
282      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
283      * for the given user. The caller is expected to launch this activity using
284      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
285      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
286      *
287      * @return the intent for launching the activity or null if no password is required.
288      *
289      * @hide
290      */
createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId)291     public Intent createConfirmDeviceCredentialIntent(
292             CharSequence title, CharSequence description, int userId) {
293         if (!isDeviceSecure(userId)) return null;
294         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
295         intent.putExtra(EXTRA_TITLE, title);
296         intent.putExtra(EXTRA_DESCRIPTION, description);
297         intent.putExtra(Intent.EXTRA_USER_ID, userId);
298 
299         // explicitly set the package for security
300         intent.setPackage(getSettingsPackageForIntent(intent));
301 
302         return intent;
303     }
304 
305     /**
306      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
307      * for the given user. The caller is expected to launch this activity using
308      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
309      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
310      *
311      * @param disallowBiometricsIfPolicyExists If true check if the Device Policy Manager has
312      * disabled biometrics on the device. If biometrics are disabled, fall back to PIN/pattern/pass.
313      *
314      * @return the intent for launching the activity or null if no password is required.
315      *
316      * @hide
317      */
createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId, boolean disallowBiometricsIfPolicyExists)318     public Intent createConfirmDeviceCredentialIntent(
319             CharSequence title, CharSequence description, int userId,
320             boolean disallowBiometricsIfPolicyExists) {
321         Intent intent = this.createConfirmDeviceCredentialIntent(title, description, userId);
322         if (intent != null) {
323             intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
324                     disallowBiometricsIfPolicyExists);
325         }
326         return intent;
327     }
328 
329     /**
330      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
331      * for the previous owner of the device. The caller is expected to launch this activity using
332      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
333      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
334      *
335      * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon
336      *                             clicking this button, the activity returns
337      *                             {@link #RESULT_ALTERNATE}
338      *
339      * @return the intent for launching the activity or null if the previous owner of the device
340      *         did not set a credential.
341      * @throws UnsupportedOperationException if the device does not support factory reset
342      *                                       credentials
343      * @throws IllegalStateException if the device has already been provisioned
344      * @hide
345      */
346     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
347     @SystemApi
createConfirmFactoryResetCredentialIntent( CharSequence title, CharSequence description, CharSequence alternateButtonLabel)348     public Intent createConfirmFactoryResetCredentialIntent(
349             CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
350         if (!LockPatternUtils.frpCredentialEnabled(mContext)) {
351             Log.w(TAG, "Factory reset credentials not supported.");
352             throw new UnsupportedOperationException("not supported on this device");
353         }
354 
355         // Cannot verify credential if the device is provisioned
356         if (Settings.Global.getInt(mContext.getContentResolver(),
357                 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
358             Log.e(TAG, "Factory reset credential cannot be verified after provisioning.");
359             throw new IllegalStateException("must not be provisioned yet");
360         }
361 
362         // Make sure we have a credential
363         try {
364             IPersistentDataBlockService pdb = IPersistentDataBlockService.Stub.asInterface(
365                     ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE));
366             if (pdb == null) {
367                 Log.e(TAG, "No persistent data block service");
368                 throw new UnsupportedOperationException("not supported on this device");
369             }
370             // The following will throw an UnsupportedOperationException if the device does not
371             // support factory reset credentials (or something went wrong retrieving it).
372             if (!pdb.hasFrpCredentialHandle()) {
373                 Log.i(TAG, "The persistent data block does not have a factory reset credential.");
374                 return null;
375             }
376         } catch (RemoteException e) {
377             throw e.rethrowFromSystemServer();
378         }
379 
380         Intent intent = new Intent(ACTION_CONFIRM_FRP_CREDENTIAL);
381         intent.putExtra(EXTRA_TITLE, title);
382         intent.putExtra(EXTRA_DESCRIPTION, description);
383         intent.putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel);
384 
385         // explicitly set the package for security
386         intent.setPackage(getSettingsPackageForIntent(intent));
387 
388         return intent;
389     }
390 
391     /**
392      * Get an Intent to launch an activity to prompt the user to confirm the
393      * credentials (pin, pattern or password) of a remote device.
394      * @param session contains information necessary to start remote device credential validation.
395      * @param remoteLockscreenValidationServiceComponent
396      *          the {@link ComponentName} of the implementation of
397      *          {@link android.service.remotelockscreenvalidation.RemoteLockscreenValidationService}
398      * @param checkboxLabel if not empty, a checkbox is provided with the given label. When checked,
399      *                      the validated remote device credential will be set as the device lock of
400      *                      the current device.
401      * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon
402      *                             clicking this button, the activity returns
403      *                             {@link #RESULT_ALTERNATE}.
404      * @hide
405      */
406     @SystemApi
407     @RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN)
408     @NonNull
createConfirmDeviceCredentialForRemoteValidationIntent( @onNull RemoteLockscreenValidationSession session, @NonNull ComponentName remoteLockscreenValidationServiceComponent, @Nullable CharSequence title, @Nullable CharSequence description, @Nullable CharSequence checkboxLabel, @Nullable CharSequence alternateButtonLabel)409     public Intent createConfirmDeviceCredentialForRemoteValidationIntent(
410             @NonNull RemoteLockscreenValidationSession session,
411             @NonNull ComponentName remoteLockscreenValidationServiceComponent,
412             @Nullable CharSequence title,
413             @Nullable CharSequence description,
414             @Nullable CharSequence checkboxLabel,
415             @Nullable CharSequence alternateButtonLabel) {
416         Intent intent = new Intent(ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL)
417                 .putExtra(EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION, session)
418                 .putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent)
419                 .putExtra(EXTRA_TITLE, title)
420                 .putExtra(EXTRA_DESCRIPTION, description)
421                 .putExtra(EXTRA_CHECKBOX_LABEL, checkboxLabel)
422                 .putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel);
423 
424         // explicitly set the package for security
425         intent.setPackage(getSettingsPackageForIntent(intent));
426 
427         return intent;
428     }
429 
430     /**
431      * Controls whether notifications can be shown atop a securely locked screen in their full
432      * private form (same as when the device is unlocked).
433      *
434      * <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration.
435      * The result is that private notifications are only shown if all sources allow it.
436      *
437      * @param allow secure notifications can be shown if {@code true},
438      * secure notifications cannot be shown if {@code false}
439      * @hide
440      */
441     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
442     @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
443     @SystemApi
setPrivateNotificationsAllowed(boolean allow)444     public void setPrivateNotificationsAllowed(boolean allow) {
445         try {
446             mNotificationManager.setPrivateNotificationsAllowed(allow);
447         } catch (RemoteException e) {
448             throw e.rethrowFromSystemServer();
449         }
450     }
451 
452     /**
453      * Returns whether notifications can be shown atop a securely locked screen in their full
454      * private form (same as when the device is unlocked).
455      *
456      * @return {@code true} if secure notifications can be shown, {@code false} otherwise.
457      * By default, private notifications are allowed.
458      * @hide
459      */
460     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
461     @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
462     @SystemApi
getPrivateNotificationsAllowed()463     public boolean getPrivateNotificationsAllowed() {
464         try {
465             return mNotificationManager.getPrivateNotificationsAllowed();
466         } catch (RemoteException e) {
467             throw e.rethrowFromSystemServer();
468         }
469     }
470 
getSettingsPackageForIntent(Intent intent)471     private String getSettingsPackageForIntent(Intent intent) {
472         List<ResolveInfo> resolveInfos = mContext.getPackageManager()
473                 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
474         for (int i = 0; i < resolveInfos.size(); i++) {
475             return resolveInfos.get(i).activityInfo.packageName;
476         }
477 
478         return "com.android.settings";
479     }
480 
481     /**
482      * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows
483      * you to temporarily disable / reenable the keyguard (lock screen).
484      *
485      * @deprecated Use {@link android.R.attr#showWhenLocked} or {@link
486      *   android.app.Activity#setShowWhenLocked(boolean)} instead. This allows you to seamlessly
487      *   occlude and unocclude the keyguard as your application moves in and out of the foreground
488      *   and does not require that any special permissions be requested.
489      */
490     @Deprecated
491     public class KeyguardLock {
492         private final IBinder mToken = new Binder();
493         private final String mTag;
494 
KeyguardLock(String tag)495         KeyguardLock(String tag) {
496             mTag = tag;
497         }
498 
499         /**
500          * Disable the keyguard from showing.  If the keyguard is currently
501          * showing, hide it.  The keyguard will be prevented from showing again
502          * until {@link #reenableKeyguard()} is called.
503          * <p>
504          * This only works if the keyguard is not secure.
505          * <p>
506          * A good place to call this is from {@link android.app.Activity#onResume()}
507          *
508          * @see KeyguardManager#isKeyguardSecure()
509          * @see #reenableKeyguard()
510          */
511         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
disableKeyguard()512         public void disableKeyguard() {
513             try {
514                 mWM.disableKeyguard(mToken, mTag, mContext.getUserId());
515             } catch (RemoteException ex) {
516             }
517         }
518 
519         /**
520          * Reenable the keyguard.  The keyguard will reappear if the previous
521          * call to {@link #disableKeyguard()} caused it to be hidden.
522          *
523          * A good place to call this is from {@link android.app.Activity#onPause()}
524          *
525          * @see #disableKeyguard()
526          */
527         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
reenableKeyguard()528         public void reenableKeyguard() {
529             try {
530                 mWM.reenableKeyguard(mToken, mContext.getUserId());
531             } catch (RemoteException ex) {
532             }
533         }
534     }
535 
536     /**
537      * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
538      * caller of result.
539      *
540      * @deprecated Use {@link KeyguardDismissCallback}
541      */
542     @Deprecated
543     public interface OnKeyguardExitResult {
544 
545         /**
546          * @param success True if the user was able to authenticate, false if
547          *   not.
548          */
onKeyguardExitResult(boolean success)549         void onKeyguardExitResult(boolean success);
550     }
551 
552     /**
553      * Callback passed to
554      * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardDismissCallback)}
555      * to notify caller of result.
556      */
557     public static abstract class KeyguardDismissCallback {
558 
559         /**
560          * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
561          * available, not showing or when the activity requesting the Keyguard dismissal isn't
562          * showing or isn't showing behind Keyguard.
563          */
onDismissError()564         public void onDismissError() { }
565 
566         /**
567          * Called when dismissing Keyguard has succeeded and the device is now unlocked.
568          */
onDismissSucceeded()569         public void onDismissSucceeded() { }
570 
571         /**
572          * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
573          * operation or the bouncer was hidden for some other reason.
574          */
onDismissCancelled()575         public void onDismissCancelled() { }
576     }
577 
578     /**
579      * Callback passed to
580      * {@link KeyguardManager#addWeakEscrowToken}
581      * to notify caller of state change.
582      * @hide
583      */
584     @SystemApi
585     public interface WeakEscrowTokenActivatedListener {
586         /**
587          * The method to be called when the token is activated.
588          * @param handle 64 bit handle corresponding to the escrow token
589          * @param user user for whom the weak escrow token has been added
590          */
onWeakEscrowTokenActivated(long handle, @NonNull UserHandle user)591         void onWeakEscrowTokenActivated(long handle, @NonNull UserHandle user);
592     }
593 
594     /**
595      * Listener passed to
596      * {@link KeyguardManager#registerWeakEscrowTokenRemovedListener} and
597      * {@link KeyguardManager#unregisterWeakEscrowTokenRemovedListener}
598      * to notify caller of an weak escrow token has been removed.
599      * @hide
600      */
601     @SystemApi
602     public interface WeakEscrowTokenRemovedListener {
603         /**
604          * The method to be called when the token is removed.
605          * @param handle 64 bit handle corresponding to the escrow token
606          * @param user user for whom the escrow token has been added
607          */
onWeakEscrowTokenRemoved(long handle, @NonNull UserHandle user)608         void onWeakEscrowTokenRemoved(long handle, @NonNull UserHandle user);
609     }
610 
KeyguardManager(Context context)611     KeyguardManager(Context context) throws ServiceNotFoundException {
612         mContext = context;
613         mLockPatternUtils = new LockPatternUtils(context);
614         mWM = WindowManagerGlobal.getWindowManagerService();
615         mAm = ActivityManager.getService();
616         mTrustManager = ITrustManager.Stub.asInterface(
617                 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
618         mNotificationManager = INotificationManager.Stub.asInterface(
619                 ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
620     }
621 
622     /**
623      * Enables you to temporarily disable / reenable the keyguard (lock screen).
624      *
625      * @param tag A tag that informally identifies who you are (for debugging who
626      *   is disabling the keyguard).
627      *
628      * @return A {@link KeyguardLock} handle to use to disable and reenable the
629      *   keyguard.
630      *
631      * @deprecated Use {@link android.R.attr#showWhenLocked} or {@link
632      *   android.app.Activity#setShowWhenLocked(boolean)} instead. This allows you to seamlessly
633      *   occlude and unocclude the keyguard as your application moves in and out of the foreground
634      *   and does not require that any special permissions be requested.
635      */
636     @Deprecated
newKeyguardLock(String tag)637     public KeyguardLock newKeyguardLock(String tag) {
638         return new KeyguardLock(tag);
639     }
640 
641     /**
642      * Returns whether the lock screen (also known as Keyguard) is showing.
643      * <p>
644      * Specifically, this returns {@code true} in the following cases:
645      * <ul>
646      *   <li>The lock screen is showing in the foreground.</li>
647      *   <li>The lock screen is showing, but it is occluded by an activity that is showing on top of
648      *   it. A common example is the phone app receiving a call or making an emergency call.</li>
649      *   <li>The lock screen was showing but is temporarily disabled as a result of <a
650      *   href="https://developer.android.com/work/dpc/dedicated-devices/lock-task-mode">lock task
651      *   mode</a> or an app using the deprecated {@link KeyguardLock} API.</li>
652      * </ul>
653      * <p>
654      * "Showing" refers to a logical state of the UI, regardless of whether the screen happens to be
655      * on. When the power button is pressed on an unlocked device, the lock screen starts "showing"
656      * immediately when the screen turns off.
657      * <p>
658      * This method does not distinguish a lock screen that is requiring authentication (e.g. with
659      * PIN, pattern, password, or biometric) from a lock screen that is trivially dismissible (e.g.
660      * with swipe). It also does not distinguish a lock screen requesting a SIM card PIN from a
661      * normal device lock screen. Finally, it always returns the global lock screen state and does
662      * not consider the {@link Context}'s user specifically.
663      * <p>
664      * Note that {@code isKeyguardLocked()} is confusingly named and probably should be called
665      * {@code isKeyguardShowing()}. On many devices, the lock screen displays an <i>unlocked</i>
666      * padlock icon when it is trivially dismissible. As mentioned above, {@code isKeyguardLocked()}
667      * actually returns {@code true} in this case, not {@code false} as might be expected. {@link
668      * #isDeviceLocked()} is an alternative API that has slightly different semantics.
669      *
670      * @return {@code true} if the lock screen is showing
671      * @see #isDeviceLocked()
672      */
isKeyguardLocked()673     public boolean isKeyguardLocked() {
674         try {
675             return mWM.isKeyguardLocked();
676         } catch (RemoteException ex) {
677             return false;
678         }
679     }
680 
681     /**
682      * Returns whether the user has a secure lock screen or there is a locked SIM card.
683      * <p>
684      * Specifically, this returns {@code true} if at least one of the following is true:
685      * <ul>
686      *   <li>The {@link Context}'s user has a secure lock screen. A full user or a profile that uses
687      *   a separate challenge has a secure lock screen if its lock screen is set to PIN, pattern, or
688      *   password, as opposed to swipe or none. A profile that uses a unified challenge is
689      *   considered to have a secure lock screen if and only if its parent user has a secure lock
690      *   screen.</li>
691      *   <li>At least one SIM card is currently locked and requires a PIN.</li>
692      * </ul>
693      * <p>
694      * This method does not consider whether the lock screen is currently showing or not.
695      * <p>
696      * See also {@link #isDeviceSecure()} which excludes locked SIM cards.
697      *
698      * @return {@code true} if the user has a secure lock screen or there is a locked SIM card
699      * @see #isDeviceSecure()
700      */
isKeyguardSecure()701     public boolean isKeyguardSecure() {
702         try {
703             return mWM.isKeyguardSecure(mContext.getUserId());
704         } catch (RemoteException ex) {
705             return false;
706         }
707     }
708 
709     /**
710      * Returns whether the lock screen is showing.
711      * <p>
712      * This is exactly the same as {@link #isKeyguardLocked()}.
713      *
714      * @return the value of {@link #isKeyguardLocked()}
715      * @deprecated Use {@link #isKeyguardLocked()} instead.
716      */
inKeyguardRestrictedInputMode()717     public boolean inKeyguardRestrictedInputMode() {
718         return isKeyguardLocked();
719     }
720 
721     /**
722      * Returns whether the device is currently locked for the user.
723      * <p>
724      * This method returns the device locked state for the {@link Context}'s user. The device is
725      * considered to be locked for a user when the user's apps are currently inaccessible and some
726      * form of lock screen authentication is required to regain access to them. The lock screen
727      * authentication typically uses PIN, pattern, password, or biometric. Some devices may support
728      * additional methods, such as unlock using a paired smartwatch. "Swipe" does not count as
729      * authentication; if the lock screen is dismissible with swipe, for example due to the lock
730      * screen being set to Swipe or due to the device being kept unlocked by being near a trusted
731      * bluetooth device or in a trusted location, the device is considered unlocked.
732      * <div class="note">
733      * <p>
734      * <b>Note:</b> In the case of multiple full users, each user can have their own lock screen
735      * authentication configured. The device-locked state may differ between different users. For
736      * example, the device may be unlocked for the current user, but locked for a non-current user
737      * if lock screen authentication would be required to access that user's apps after switching to
738      * that user.
739      * <p>
740      * In the case of a profile, when the device goes to the main lock screen, up to two layers of
741      * authentication may be required to regain access to the profile's apps: one to unlock the main
742      * lock screen, and one to unlock the profile (when a separate profile challenge is required).
743      * For a profile, the device is considered to be locked as long as any challenge remains, either
744      * the parent user's challenge (when applicable) or the profile's challenge (when applicable).
745      * </div>
746      *
747      * @return {@code true} if the device is currently locked for the user
748      * @see #isKeyguardLocked()
749      */
isDeviceLocked()750     public boolean isDeviceLocked() {
751         return isDeviceLocked(mContext.getUserId(), mContext.getDeviceId());
752     }
753 
754     /**
755      * Per-user version of {@link #isDeviceLocked()}.
756      *
757      * @hide
758      */
759     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isDeviceLocked(int userId)760     public boolean isDeviceLocked(int userId) {
761         return isDeviceLocked(userId, mContext.getDeviceId());
762     }
763 
764     /**
765      * Per-user per-device version of {@link #isDeviceLocked()}.
766      *
767      * @hide
768      */
isDeviceLocked(@serIdInt int userId, int deviceId)769     public boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
770         try {
771             return mTrustManager.isDeviceLocked(userId, deviceId);
772         } catch (RemoteException e) {
773             return false;
774         }
775     }
776 
777     /**
778      * Returns whether the user has a secure lock screen.
779      * <p>
780      * This returns {@code true} if the {@link Context}'s user has a secure lock screen. A full user
781      * or a profile that uses a separate challenge has a secure lock screen if its lock screen is
782      * set to PIN, pattern, or password, as opposed to swipe or none. A profile that uses a unified
783      * challenge is considered to have a secure lock screen if and only if its parent user has a
784      * secure lock screen.
785      * <p>
786      * This method does not consider whether the lock screen is currently showing or not.
787      * <p>
788      * See also {@link #isKeyguardSecure()} which includes locked SIM cards.
789      *
790      * @return {@code true} if the user has a secure lock screen
791      * @see #isKeyguardSecure()
792      */
isDeviceSecure()793     public boolean isDeviceSecure() {
794         return isDeviceSecure(mContext.getUserId(), mContext.getDeviceId());
795     }
796 
797     /**
798      * Per-user version of {@link #isDeviceSecure()}.
799      *
800      * @hide
801      */
802     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isDeviceSecure(int userId)803     public boolean isDeviceSecure(int userId) {
804         return isDeviceSecure(userId, mContext.getDeviceId());
805     }
806 
807     /**
808      * Per-user per-device version of {@link #isDeviceSecure()}.
809      *
810      * @hide
811      */
isDeviceSecure(@serIdInt int userId, int deviceId)812     public boolean isDeviceSecure(@UserIdInt int userId, int deviceId) {
813         try {
814             return mTrustManager.isDeviceSecure(userId, deviceId);
815         } catch (RemoteException e) {
816             return false;
817         }
818     }
819 
820     /**
821      * Requests that the Keyguard (lock screen) be dismissed if it is currently showing.
822      * <p>
823      * If the Keyguard is not secure or the device is currently in a trusted state, calling this
824      * method will immediately dismiss the Keyguard without any user interaction.
825      * <p>
826      * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
827      * UI so the user can enter their credentials.
828      * <p>
829      * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true,
830      * the screen will turn on when the keyguard is dismissed.
831      *
832      * @param activity The activity requesting the dismissal. The activity must either be visible
833      *                 by using {@link android.R.attr#showWhenLocked} or {@link
834      *                 android.app.Activity#setShowWhenLocked(boolean)}, or must be in a state in
835      *                 which it would be visible if Keyguard would not be hiding it. If that's not
836      *                 the case, the request will fail immediately and
837      *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
838      * @param callback The callback to be called if the request to dismiss Keyguard was successful
839      *                 or {@code null} if the caller isn't interested in knowing the result. The
840      *                 callback will not be invoked if the activity was destroyed before the
841      *                 callback was received.
842      */
requestDismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback)843     public void requestDismissKeyguard(@NonNull Activity activity,
844             @Nullable KeyguardDismissCallback callback) {
845         requestDismissKeyguard(activity, null /* message */, callback);
846     }
847 
848     /**
849      * Requests that the Keyguard (lock screen) be dismissed if it is currently showing.
850      * <p>
851      * If the Keyguard is not secure or the device is currently in a trusted state, calling this
852      * method will immediately dismiss the Keyguard without any user interaction.
853      * <p>
854      * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
855      * UI so the user can enter their credentials.
856      * <p>
857      * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true,
858      * the screen will turn on when the keyguard is dismissed.
859      *
860      * @param activity The activity requesting the dismissal. The activity must either be visible
861      *                 by using {@link android.R.attr#showWhenLocked} or {@link
862      *                 android.app.Activity#setShowWhenLocked(boolean)}, or must be in a state in
863      *                 which it would be visible if Keyguard would not be hiding it. If that's not
864      *                 the case, the request will fail immediately and
865      *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
866      * @param message  A message that will be shown in the keyguard explaining why the user
867      *                 would want to dismiss it.
868      * @param callback The callback to be called if the request to dismiss Keyguard was successful
869      *                 or {@code null} if the caller isn't interested in knowing the result. The
870      *                 callback will not be invoked if the activity was destroyed before the
871      *                 callback was received.
872      * @hide
873      */
874     @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE)
875     @SystemApi
requestDismissKeyguard(@onNull Activity activity, @Nullable CharSequence message, @Nullable KeyguardDismissCallback callback)876     public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message,
877             @Nullable KeyguardDismissCallback callback) {
878         ActivityClient.getInstance().dismissKeyguard(
879                 activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
880             @Override
881             public void onDismissError() throws RemoteException {
882                 if (callback != null && !activity.isDestroyed()) {
883                     activity.mHandler.post(callback::onDismissError);
884                 }
885             }
886 
887             @Override
888             public void onDismissSucceeded() throws RemoteException {
889                 if (callback != null && !activity.isDestroyed()) {
890                     activity.mHandler.post(callback::onDismissSucceeded);
891                 }
892             }
893 
894             @Override
895             public void onDismissCancelled() throws RemoteException {
896                 if (callback != null && !activity.isDestroyed()) {
897                     activity.mHandler.post(callback::onDismissCancelled);
898                 }
899             }
900         }, message);
901     }
902 
903     /**
904      * Exit the keyguard securely.  The use case for this api is that, after
905      * disabling the keyguard, your app, which was granted permission to
906      * disable the keyguard and show a limited amount of information deemed
907      * safe without the user getting past the keyguard, needs to navigate to
908      * something that is not safe to view without getting past the keyguard.
909      *
910      * This will, if the keyguard is secure, bring up the unlock screen of
911      * the keyguard.
912      *
913      * @param callback Lets you know whether the operation was successful and
914      *   it is safe to launch anything that would normally be considered safe
915      *   once the user has gotten past the keyguard.
916      *
917      * @deprecated Use {@link android.R.attr#showWhenLocked} or {@link
918      *   android.app.Activity#setShowWhenLocked(boolean)} to seamlessly occlude and unocclude the
919      *   keyguard as your application moves in and out of the foreground, without requiring any
920      *   special permissions. Use {@link #requestDismissKeyguard(android.app.Activity,
921      *   KeyguardDismissCallback)} to request dismissal of the keyguard.
922      */
923     @Deprecated
924     @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
exitKeyguardSecurely(final OnKeyguardExitResult callback)925     public void exitKeyguardSecurely(final OnKeyguardExitResult callback) {
926         try {
927             mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() {
928                 public void onKeyguardExitResult(boolean success) throws RemoteException {
929                     if (callback != null) {
930                         callback.onKeyguardExitResult(success);
931                     }
932                 }
933             });
934         } catch (RemoteException e) {
935 
936         }
937     }
938 
939     /** @hide */
940     @VisibleForTesting
checkInitialLockMethodUsage()941     public boolean checkInitialLockMethodUsage() {
942         if (!hasPermission(Manifest.permission.SET_INITIAL_LOCK)) {
943             throw new SecurityException("Requires SET_INITIAL_LOCK permission.");
944         }
945         return true;
946     }
947 
hasPermission(String permission)948     private boolean hasPermission(String permission) {
949         return PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
950                 permission);
951     }
952 
953     /**
954     * Determine if a given password is valid based off its lock type and expected complexity level.
955     *
956     * @param lockType - type of lock as specified in {@link LockTypes}
957     * @param password - password to validate; this has the same encoding
958     *        as the output of String#getBytes
959     * @param complexity - complexity level imposed by the requester
960     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
961     * @return {@code true} if the password is valid, false otherwise
962     * @hide
963     */
964     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
965     @SystemApi
isValidLockPasswordComplexity(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)966     public boolean isValidLockPasswordComplexity(@LockTypes int lockType, @NonNull byte[] password,
967             @PasswordComplexity int complexity) {
968         if (!checkInitialLockMethodUsage()) {
969             return false;
970         }
971         Objects.requireNonNull(password, "Password cannot be null.");
972         complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
973         PasswordMetrics adminMetrics =
974                 mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
975         try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
976             return PasswordMetrics.validateCredential(adminMetrics, complexity,
977                     credential).size() == 0;
978         }
979     }
980 
981     /**
982     * Determine the minimum allowable length for a lock type for a given complexity level.
983     *
984     * @param isPin - whether this is a PIN-type password (only digits)
985     * @param complexity - complexity level imposed by the requester
986     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
987     * @return minimum allowable password length
988     * @hide
989     */
990     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
991     @SystemApi
getMinLockLength(boolean isPin, @PasswordComplexity int complexity)992     public int getMinLockLength(boolean isPin, @PasswordComplexity int complexity) {
993         if (!checkInitialLockMethodUsage()) {
994             return -1;
995         }
996         complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
997         PasswordMetrics adminMetrics =
998                 mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
999         PasswordMetrics minMetrics =
1000                 PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity);
1001         return minMetrics.length;
1002     }
1003 
1004     /**
1005     * Set the lockscreen password after validating against its expected complexity level.
1006     *
1007     * Below {@link android.os.Build.VERSION_CODES#S_V2}, this API will only work
1008     * when {@link PackageManager.FEATURE_AUTOMOTIVE} is present.
1009     * @param lockType - type of lock as specified in {@link LockTypes}
1010     * @param password - password to validate; this has the same encoding
1011     *        as the output of String#getBytes
1012     * @param complexity - complexity level imposed by the requester
1013     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
1014     * @return {@code true} if the lock is successfully set, false otherwise
1015     * @hide
1016     */
1017     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
1018     @SystemApi
setLock(@ockTypes int lockType, @NonNull byte[] password, @PasswordComplexity int complexity)1019     public boolean setLock(@LockTypes int lockType, @NonNull byte[] password,
1020             @PasswordComplexity int complexity) {
1021         if (!checkInitialLockMethodUsage()) {
1022             return false;
1023         }
1024 
1025         int userId = mContext.getUserId();
1026         if (isDeviceSecure(userId)) {
1027             Log.e(TAG, "Password already set, rejecting call to setLock");
1028             return false;
1029         }
1030         if (!isValidLockPasswordComplexity(lockType, password, complexity)) {
1031             Log.e(TAG, "Password is not valid, rejecting call to setLock");
1032             return false;
1033         }
1034         boolean success;
1035         try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
1036             success = mLockPatternUtils.setLockCredential(
1037                     credential,
1038                     /* savedPassword= */ LockscreenCredential.createNone(),
1039                     userId);
1040         } catch (Exception e) {
1041             Log.e(TAG, "Save lock exception", e);
1042             success = false;
1043         } finally {
1044             Arrays.fill(password, (byte) 0);
1045         }
1046         return success;
1047     }
1048 
1049     /**
1050      * Create a weak escrow token for the current user, which can later be used to unlock FBE
1051      * or change user password.
1052      *
1053      * After adding, if the user currently  has a secure lockscreen, they will need to perform a
1054      * confirm credential operation in order to activate the token for future use. If the user
1055      * has no secure lockscreen, then the token is activated immediately.
1056      *
1057      * If the user changes or removes the lockscreen password, any activated weak escrow token will
1058      * be removed.
1059      *
1060      * @return a unique 64-bit token handle which is needed to refer to this token later.
1061      * @hide
1062      */
1063     @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
1064     @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN)
1065     @SystemApi
addWeakEscrowToken(@onNull byte[] token, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull WeakEscrowTokenActivatedListener listener)1066     public long addWeakEscrowToken(@NonNull byte[] token, @NonNull UserHandle user,
1067             @NonNull @CallbackExecutor Executor executor,
1068             @NonNull WeakEscrowTokenActivatedListener listener) {
1069         Objects.requireNonNull(token, "Token cannot be null.");
1070         Objects.requireNonNull(user, "User cannot be null.");
1071         Objects.requireNonNull(executor, "Executor cannot be null.");
1072         Objects.requireNonNull(listener, "Listener cannot be null.");
1073         int userId = user.getIdentifier();
1074         IWeakEscrowTokenActivatedListener internalListener =
1075                 new IWeakEscrowTokenActivatedListener.Stub() {
1076             @Override
1077             public void onWeakEscrowTokenActivated(long handle, int userId) {
1078                 UserHandle user = UserHandle.of(userId);
1079                 final long restoreToken = Binder.clearCallingIdentity();
1080                 try {
1081                     executor.execute(() -> listener.onWeakEscrowTokenActivated(handle, user));
1082                 } finally {
1083                     Binder.restoreCallingIdentity(restoreToken);
1084                 }
1085                 Log.i(TAG, "Weak escrow token activated.");
1086             }
1087         };
1088         return mLockPatternUtils.addWeakEscrowToken(token, userId, internalListener);
1089     }
1090 
1091     /**
1092      * Remove a weak escrow token.
1093      *
1094      * @return {@code true} if the given handle refers to a valid weak token previously returned
1095      * from {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise.
1096      * @hide
1097      */
1098     @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
1099     @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN)
1100     @SystemApi
removeWeakEscrowToken(long handle, @NonNull UserHandle user)1101     public boolean removeWeakEscrowToken(long handle, @NonNull UserHandle user) {
1102         Objects.requireNonNull(user, "User cannot be null.");
1103         return mLockPatternUtils.removeWeakEscrowToken(handle, user.getIdentifier());
1104     }
1105 
1106     /**
1107      * Check if the given weak escrow token is active or not.
1108      * @hide
1109      */
1110     @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
1111     @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN)
1112     @SystemApi
isWeakEscrowTokenActive(long handle, @NonNull UserHandle user)1113     public boolean isWeakEscrowTokenActive(long handle, @NonNull UserHandle user) {
1114         Objects.requireNonNull(user, "User cannot be null.");
1115         return mLockPatternUtils.isWeakEscrowTokenActive(handle, user.getIdentifier());
1116     }
1117 
1118     /**
1119      * Check if the given weak escrow token is validate.
1120      * @hide
1121      */
1122     @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
1123     @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN)
1124     @SystemApi
isWeakEscrowTokenValid(long handle, @NonNull byte[] token, @NonNull UserHandle user)1125     public boolean isWeakEscrowTokenValid(long handle, @NonNull byte[] token,
1126             @NonNull UserHandle user) {
1127         Objects.requireNonNull(token, "Token cannot be null.");
1128         Objects.requireNonNull(user, "User cannot be null.");
1129         return mLockPatternUtils.isWeakEscrowTokenValid(handle, token, user.getIdentifier());
1130     }
1131 
1132     /**
1133      * Register the given WeakEscrowTokenRemovedListener.
1134      *
1135      * @return {@code true} if the listener is registered successfully, return false otherwise.
1136      * @hide
1137      */
1138     @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
1139     @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN)
1140     @SystemApi
registerWeakEscrowTokenRemovedListener( @onNull @allbackExecutor Executor executor, @NonNull WeakEscrowTokenRemovedListener listener)1141     public boolean registerWeakEscrowTokenRemovedListener(
1142             @NonNull @CallbackExecutor Executor executor,
1143             @NonNull WeakEscrowTokenRemovedListener listener) {
1144         Objects.requireNonNull(listener, "Listener cannot be null.");
1145         Objects.requireNonNull(executor, "Executor cannot be null.");
1146         Preconditions.checkArgument(!mListeners.containsKey(listener),
1147                 "Listener already registered: %s", listener);
1148         IWeakEscrowTokenRemovedListener internalListener =
1149                 new IWeakEscrowTokenRemovedListener.Stub() {
1150             @Override
1151             public void onWeakEscrowTokenRemoved(long handle, int userId) {
1152                 UserHandle user = UserHandle.of(userId);
1153                 final long token = Binder.clearCallingIdentity();
1154                 try {
1155                     executor.execute(() -> listener.onWeakEscrowTokenRemoved(handle, user));
1156                 } finally {
1157                     Binder.restoreCallingIdentity(token);
1158                 }
1159             }
1160         };
1161         if (mLockPatternUtils.registerWeakEscrowTokenRemovedListener(internalListener)) {
1162             mListeners.put(listener, internalListener);
1163             return true;
1164         } else {
1165             Log.e(TAG, "Listener failed to register");
1166             return false;
1167         }
1168     }
1169 
1170     /**
1171      * Unregister the given WeakEscrowTokenRemovedListener.
1172      *
1173      * @return {@code true} if the listener is unregistered successfully, return false otherwise.
1174      * @hide
1175      */
1176     @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
1177     @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN)
1178     @SystemApi
unregisterWeakEscrowTokenRemovedListener( @onNull WeakEscrowTokenRemovedListener listener)1179     public boolean unregisterWeakEscrowTokenRemovedListener(
1180             @NonNull WeakEscrowTokenRemovedListener listener) {
1181         Objects.requireNonNull(listener, "Listener cannot be null.");
1182         IWeakEscrowTokenRemovedListener internalListener = mListeners.get(listener);
1183         Preconditions.checkArgument(internalListener != null, "Listener was not registered");
1184         if (mLockPatternUtils.unregisterWeakEscrowTokenRemovedListener(internalListener)) {
1185             mListeners.remove(listener);
1186             return true;
1187         } else {
1188             Log.e(TAG, "Listener failed to unregister.");
1189             return false;
1190         }
1191     }
1192 
1193     /**
1194      * Set the lockscreen password to {@code newPassword} after validating the current password
1195      * against {@code currentPassword}.
1196      * <p>If no password is currently set, {@code currentPassword} should be set to {@code null}.
1197      * <p>To clear the current password, {@code newPassword} should be set to {@code null}.
1198      *
1199      * @return {@code true} if password successfully set.
1200      *
1201      * @throws IllegalArgumentException if {@code newLockType} or {@code currentLockType}
1202      * is invalid.
1203      *
1204      * @hide
1205      */
1206     @TestApi
1207     @RequiresPermission(anyOf = {
1208             Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS,
1209             Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE
1210     })
setLock(@ockTypes int newLockType, @Nullable byte[] newPassword, @LockTypes int currentLockType, @Nullable byte[] currentPassword)1211     public boolean setLock(@LockTypes int newLockType, @Nullable byte[] newPassword,
1212             @LockTypes int currentLockType, @Nullable byte[] currentPassword) {
1213         final int userId = mContext.getUserId();
1214         try (LockscreenCredential currentCredential = createLockscreenCredential(
1215                 currentLockType, currentPassword);
1216                 LockscreenCredential newCredential = createLockscreenCredential(
1217                         newLockType, newPassword)) {
1218             PasswordMetrics adminMetrics =
1219                     mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
1220             List<PasswordValidationError> errors = PasswordMetrics.validateCredential(adminMetrics,
1221                     DevicePolicyManager.PASSWORD_COMPLEXITY_NONE, newCredential);
1222             if (!errors.isEmpty()) {
1223                 Log.e(TAG, "New credential is not valid: " + errors.get(0));
1224                 return false;
1225             }
1226             return mLockPatternUtils.setLockCredential(newCredential, currentCredential, userId);
1227         }
1228     }
1229 
1230     /**
1231      * Verifies the current lock credentials against {@code password}.
1232      * <p>To check if no password is set, {@code password} should be set to {@code null}.
1233      *
1234      * @return {@code true} if credentials match
1235      *
1236      * @throws IllegalArgumentException if {@code lockType} is invalid.
1237      *
1238      * @hide
1239      */
1240     @TestApi
1241     @RequiresPermission(anyOf = {
1242             Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS,
1243             Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE
1244     })
checkLock(@ockTypes int lockType, @Nullable byte[] password)1245     public boolean checkLock(@LockTypes int lockType, @Nullable byte[] password) {
1246         try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
1247             final VerifyCredentialResponse response = mLockPatternUtils.verifyCredential(
1248                     credential, mContext.getUserId(), /* flags= */ 0);
1249             if (response == null) {
1250                 return false;
1251             }
1252             return response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK;
1253         }
1254     }
1255 
1256     /** Starts a session to verify lockscreen credentials provided by a remote device.
1257      *
1258      * The session and corresponding public key will be removed when
1259      * {@code validateRemoteLockScreen} provides a correct guess or after 10 minutes of inactivity.
1260      *
1261      * @return information necessary to perform remote lock screen credentials check, including
1262 
1263      * short lived public key used to send encrypted guess and lock screen type.
1264      *
1265      * @throws IllegalStateException if lock screen is not set
1266      *
1267      * @hide
1268      */
1269     @SystemApi
1270     @RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN)
1271     @NonNull
startRemoteLockscreenValidation()1272     public RemoteLockscreenValidationSession startRemoteLockscreenValidation() {
1273         return mLockPatternUtils.startRemoteLockscreenValidation();
1274     }
1275 
1276     /**
1277      * Verifies credentials guess from a remote device.
1278      *
1279      * <p>Secret must be encrypted using {@code SecureBox} library
1280      * with public key from {@code RemoteLockscreenValidationSession}
1281      * and header set to {@code "encrypted_remote_credentials"} in UTF-8 encoding.
1282      *
1283      * @throws IllegalStateException if there was a decryption error.
1284      *
1285      * @hide
1286      */
1287     @SystemApi
1288     @RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN)
1289     @NonNull
validateRemoteLockscreen( @onNull byte[] encryptedCredential)1290     public RemoteLockscreenValidationResult validateRemoteLockscreen(
1291             @NonNull byte[] encryptedCredential) {
1292         return mLockPatternUtils.validateRemoteLockscreen(encryptedCredential);
1293     }
1294 
createLockscreenCredential( @ockTypes int lockType, @Nullable byte[] password)1295     private LockscreenCredential createLockscreenCredential(
1296             @LockTypes int lockType, @Nullable byte[] password) {
1297         if (password == null) {
1298             return LockscreenCredential.createNone();
1299         }
1300         switch (lockType) {
1301             case PASSWORD:
1302                 CharSequence passwordStr = new String(password, Charset.forName("UTF-8"));
1303                 return LockscreenCredential.createPassword(passwordStr);
1304             case PIN:
1305                 CharSequence pinStr = new String(password);
1306                 return LockscreenCredential.createPin(pinStr);
1307             case PATTERN:
1308                 List<LockPatternView.Cell> pattern =
1309                         LockPatternUtils.byteArrayToPattern(password);
1310                 return LockscreenCredential.createPattern(pattern);
1311             default:
1312                 throw new IllegalArgumentException("Unknown lock type " + lockType);
1313         }
1314     }
1315 
1316     /**
1317      * Listener for keyguard locked state changes.
1318      */
1319     @FunctionalInterface
1320     public interface KeyguardLockedStateListener {
1321         /**
1322          * Callback function that executes when the keyguard locked state changes.
1323          */
onKeyguardLockedStateChanged(boolean isKeyguardLocked)1324         void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
1325     }
1326 
1327     /**
1328      * Registers a listener to execute when the keyguard locked state changes.
1329      *
1330      * @param listener The listener to add to receive keyguard locked state changes.
1331      *
1332      * @see #isKeyguardLocked()
1333      * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
1334      */
1335     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
addKeyguardLockedStateListener(@onNull @allbackExecutor Executor executor, @NonNull KeyguardLockedStateListener listener)1336     public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
1337             @NonNull KeyguardLockedStateListener listener) {
1338         synchronized (mKeyguardLockedStateListeners) {
1339             mKeyguardLockedStateListeners.put(listener, executor);
1340             if (mKeyguardLockedStateListeners.size() > 1) {
1341                 return;
1342             }
1343             try {
1344                 mWM.addKeyguardLockedStateListener(mIKeyguardLockedStateListener);
1345             } catch (RemoteException e) {
1346                 throw e.rethrowFromSystemServer();
1347             }
1348         }
1349     }
1350 
1351     /**
1352      * Unregisters a listener that executes when the keyguard locked state changes.
1353      *
1354      * @param listener The listener to remove.
1355      *
1356      * @see #isKeyguardLocked()
1357      * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
1358      */
1359     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
removeKeyguardLockedStateListener(@onNull KeyguardLockedStateListener listener)1360     public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
1361         synchronized (mKeyguardLockedStateListeners) {
1362             mKeyguardLockedStateListeners.remove(listener);
1363             if (!mKeyguardLockedStateListeners.isEmpty()) {
1364                 return;
1365             }
1366             try {
1367                 mWM.removeKeyguardLockedStateListener(mIKeyguardLockedStateListener);
1368             } catch (RemoteException e) {
1369                 throw e.rethrowFromSystemServer();
1370             }
1371         }
1372     }
1373 }
1374