Home | History | Annotate | Download | only in widget
      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 com.android.internal.widget;
     18 
     19 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
     20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
     21 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
     22 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
     23 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
     24 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
     25 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
     26 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     27 
     28 import android.annotation.IntDef;
     29 import android.annotation.Nullable;
     30 import android.app.admin.DevicePolicyManager;
     31 import android.app.admin.PasswordMetrics;
     32 import android.app.trust.IStrongAuthTracker;
     33 import android.app.trust.TrustManager;
     34 import android.content.ComponentName;
     35 import android.content.ContentResolver;
     36 import android.content.Context;
     37 import android.content.pm.UserInfo;
     38 import android.os.AsyncTask;
     39 import android.os.Handler;
     40 import android.os.IBinder;
     41 import android.os.Looper;
     42 import android.os.Message;
     43 import android.os.RemoteException;
     44 import android.os.ServiceManager;
     45 import android.os.SystemClock;
     46 import android.os.UserHandle;
     47 import android.os.UserManager;
     48 import android.os.storage.IStorageManager;
     49 import android.os.storage.StorageManager;
     50 import android.provider.Settings;
     51 import android.text.TextUtils;
     52 import android.util.Log;
     53 import android.util.SparseIntArray;
     54 import android.util.SparseLongArray;
     55 
     56 import com.android.internal.annotations.VisibleForTesting;
     57 import com.android.server.LocalServices;
     58 import com.google.android.collect.Lists;
     59 
     60 import libcore.util.HexEncoding;
     61 
     62 import java.lang.annotation.Retention;
     63 import java.lang.annotation.RetentionPolicy;
     64 import java.nio.charset.StandardCharsets;
     65 import java.security.MessageDigest;
     66 import java.security.NoSuchAlgorithmException;
     67 import java.security.SecureRandom;
     68 import java.util.ArrayList;
     69 import java.util.Arrays;
     70 import java.util.Collection;
     71 import java.util.List;
     72 import java.util.StringJoiner;
     73 /**
     74  * Utilities for the lock pattern and its settings.
     75  */
     76 public class LockPatternUtils {
     77 
     78     private static final String TAG = "LockPatternUtils";
     79     private static final boolean DEBUG = false;
     80     private static final boolean FRP_CREDENTIAL_ENABLED = true;
     81 
     82     /**
     83      * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
     84      */
     85     public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
     86 
     87     /**
     88      * The number of incorrect attempts before which we fall back on an alternative
     89      * method of verifying the user, and resetting their lock pattern.
     90      */
     91     public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
     92 
     93     /**
     94      * The interval of the countdown for showing progress of the lockout.
     95      */
     96     public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
     97 
     98 
     99     /**
    100      * This dictates when we start telling the user that continued failed attempts will wipe
    101      * their device.
    102      */
    103     public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
    104 
    105     /**
    106      * The minimum number of dots in a valid pattern.
    107      */
    108     public static final int MIN_LOCK_PATTERN_SIZE = 4;
    109 
    110     /**
    111      * The minimum size of a valid password.
    112      */
    113     public static final int MIN_LOCK_PASSWORD_SIZE = 4;
    114 
    115     /**
    116      * The minimum number of dots the user must include in a wrong pattern
    117      * attempt for it to be counted against the counts that affect
    118      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
    119      */
    120     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
    121 
    122     public static final int CREDENTIAL_TYPE_NONE = -1;
    123 
    124     public static final int CREDENTIAL_TYPE_PATTERN = 1;
    125 
    126     public static final int CREDENTIAL_TYPE_PASSWORD = 2;
    127 
    128     /**
    129      * Special user id for triggering the FRP verification flow.
    130      */
    131     public static final int USER_FRP = UserHandle.USER_NULL + 1;
    132 
    133     @Deprecated
    134     public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
    135     public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
    136     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
    137     @Deprecated
    138     public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
    139     public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
    140     public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
    141     public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
    142     @Deprecated
    143     public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
    144             = "lockscreen.biometric_weak_fallback";
    145     @Deprecated
    146     public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
    147             = "lockscreen.biometricweakeverchosen";
    148     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
    149             = "lockscreen.power_button_instantly_locks";
    150     @Deprecated
    151     public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
    152 
    153     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
    154 
    155     private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
    156     private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
    157             Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    158 
    159     private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
    160 
    161     private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
    162     private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
    163 
    164     public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
    165     public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
    166     public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_";
    167 
    168     public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
    169     public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
    170     private static final String HISTORY_DELIMITER = ",";
    171 
    172     private final Context mContext;
    173     private final ContentResolver mContentResolver;
    174     private DevicePolicyManager mDevicePolicyManager;
    175     private ILockSettings mLockSettingsService;
    176     private UserManager mUserManager;
    177     private final Handler mHandler;
    178     private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
    179 
    180     /**
    181      * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
    182      *
    183      * This returns the lazily-peristed value and should only be used by TrustManagerService.
    184      */
    185     public boolean isTrustUsuallyManaged(int userId) {
    186         if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
    187             throw new IllegalStateException("May only be called by TrustManagerService. "
    188                     + "Use TrustManager.isTrustUsuallyManaged()");
    189         }
    190         try {
    191             return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
    192         } catch (RemoteException e) {
    193             return false;
    194         }
    195     }
    196 
    197     public void setTrustUsuallyManaged(boolean managed, int userId) {
    198         try {
    199             getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
    200         } catch (RemoteException e) {
    201             // System dead.
    202         }
    203     }
    204 
    205     public void userPresent(int userId) {
    206         try {
    207             getLockSettings().userPresent(userId);
    208         } catch (RemoteException e) {
    209             throw e.rethrowFromSystemServer();
    210         }
    211     }
    212 
    213     public static final class RequestThrottledException extends Exception {
    214         private int mTimeoutMs;
    215         public RequestThrottledException(int timeoutMs) {
    216             mTimeoutMs = timeoutMs;
    217         }
    218 
    219         /**
    220          * @return The amount of time in ms before another request may
    221          * be executed
    222          */
    223         public int getTimeoutMs() {
    224             return mTimeoutMs;
    225         }
    226 
    227     }
    228 
    229     public DevicePolicyManager getDevicePolicyManager() {
    230         if (mDevicePolicyManager == null) {
    231             mDevicePolicyManager =
    232                 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    233             if (mDevicePolicyManager == null) {
    234                 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
    235                         new IllegalStateException("Stack trace:"));
    236             }
    237         }
    238         return mDevicePolicyManager;
    239     }
    240 
    241     private UserManager getUserManager() {
    242         if (mUserManager == null) {
    243             mUserManager = UserManager.get(mContext);
    244         }
    245         return mUserManager;
    246     }
    247 
    248     private TrustManager getTrustManager() {
    249         TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
    250         if (trust == null) {
    251             Log.e(TAG, "Can't get TrustManagerService: is it running?",
    252                     new IllegalStateException("Stack trace:"));
    253         }
    254         return trust;
    255     }
    256 
    257     public LockPatternUtils(Context context) {
    258         mContext = context;
    259         mContentResolver = context.getContentResolver();
    260 
    261         Looper looper = Looper.myLooper();
    262         mHandler = looper != null ? new Handler(looper) : null;
    263     }
    264 
    265     @VisibleForTesting
    266     public ILockSettings getLockSettings() {
    267         if (mLockSettingsService == null) {
    268             ILockSettings service = ILockSettings.Stub.asInterface(
    269                     ServiceManager.getService("lock_settings"));
    270             mLockSettingsService = service;
    271         }
    272         return mLockSettingsService;
    273     }
    274 
    275     public int getRequestedMinimumPasswordLength(int userId) {
    276         return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
    277     }
    278 
    279     /**
    280      * Gets the device policy password mode. If the mode is non-specific, returns
    281      * MODE_PATTERN which allows the user to choose anything.
    282      */
    283     public int getRequestedPasswordQuality(int userId) {
    284         return getDevicePolicyManager().getPasswordQuality(null, userId);
    285     }
    286 
    287     private int getRequestedPasswordHistoryLength(int userId) {
    288         return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
    289     }
    290 
    291     public int getRequestedPasswordMinimumLetters(int userId) {
    292         return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
    293     }
    294 
    295     public int getRequestedPasswordMinimumUpperCase(int userId) {
    296         return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
    297     }
    298 
    299     public int getRequestedPasswordMinimumLowerCase(int userId) {
    300         return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
    301     }
    302 
    303     public int getRequestedPasswordMinimumNumeric(int userId) {
    304         return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
    305     }
    306 
    307     public int getRequestedPasswordMinimumSymbols(int userId) {
    308         return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
    309     }
    310 
    311     public int getRequestedPasswordMinimumNonLetter(int userId) {
    312         return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
    313     }
    314 
    315     public void reportFailedPasswordAttempt(int userId) {
    316         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
    317             return;
    318         }
    319         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
    320         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
    321     }
    322 
    323     public void reportSuccessfulPasswordAttempt(int userId) {
    324         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
    325             return;
    326         }
    327         getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
    328         getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
    329     }
    330 
    331     public void reportPasswordLockout(int timeoutMs, int userId) {
    332         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
    333             return;
    334         }
    335         getTrustManager().reportUnlockLockout(timeoutMs, userId);
    336     }
    337 
    338     public int getCurrentFailedPasswordAttempts(int userId) {
    339         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
    340             return 0;
    341         }
    342         return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
    343     }
    344 
    345     public int getMaximumFailedPasswordsForWipe(int userId) {
    346         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
    347             return 0;
    348         }
    349         return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
    350                 null /* componentName */, userId);
    351     }
    352 
    353     private byte[] verifyCredential(String credential, int type, long challenge, int userId)
    354             throws RequestThrottledException {
    355         try {
    356             VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
    357                     type, challenge, userId);
    358             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
    359                 return response.getPayload();
    360             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
    361                 throw new RequestThrottledException(response.getTimeout());
    362             } else {
    363                 return null;
    364             }
    365         } catch (RemoteException re) {
    366             return null;
    367         }
    368     }
    369 
    370     private boolean checkCredential(String credential, int type, int userId,
    371             @Nullable CheckCredentialProgressCallback progressCallback)
    372             throws RequestThrottledException {
    373         try {
    374             VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,
    375                     userId, wrapCallback(progressCallback));
    376 
    377             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
    378                 return true;
    379             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
    380                 throw new RequestThrottledException(response.getTimeout());
    381             } else {
    382                 return false;
    383             }
    384         } catch (RemoteException re) {
    385             return false;
    386         }
    387     }
    388 
    389     /**
    390      * Check to see if a pattern matches the saved pattern.
    391      * If pattern matches, return an opaque attestation that the challenge
    392      * was verified.
    393      *
    394      * @param pattern The pattern to check.
    395      * @param challenge The challenge to verify against the pattern
    396      * @return the attestation that the challenge was verified, or null.
    397      */
    398     public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
    399             throws RequestThrottledException {
    400         throwIfCalledOnMainThread();
    401         return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
    402                 userId);
    403     }
    404 
    405     /**
    406      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
    407      * always returns true.
    408      * @param pattern The pattern to check.
    409      * @return Whether the pattern matches the stored one.
    410      */
    411     public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
    412             throws RequestThrottledException {
    413         return checkPattern(pattern, userId, null /* progressCallback */);
    414     }
    415 
    416     /**
    417      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
    418      * always returns true.
    419      * @param pattern The pattern to check.
    420      * @return Whether the pattern matches the stored one.
    421      */
    422     public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,
    423             @Nullable CheckCredentialProgressCallback progressCallback)
    424             throws RequestThrottledException {
    425         throwIfCalledOnMainThread();
    426         return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
    427                 progressCallback);
    428     }
    429 
    430     /**
    431      * Check to see if a password matches the saved password.
    432      * If password matches, return an opaque attestation that the challenge
    433      * was verified.
    434      *
    435      * @param password The password to check.
    436      * @param challenge The challenge to verify against the password
    437      * @return the attestation that the challenge was verified, or null.
    438      */
    439     public byte[] verifyPassword(String password, long challenge, int userId)
    440             throws RequestThrottledException {
    441         throwIfCalledOnMainThread();
    442         return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
    443     }
    444 
    445 
    446     /**
    447      * Check to see if a password matches the saved password.
    448      * If password matches, return an opaque attestation that the challenge
    449      * was verified.
    450      *
    451      * @param password The password to check.
    452      * @param challenge The challenge to verify against the password
    453      * @return the attestation that the challenge was verified, or null.
    454      */
    455     public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
    456             int userId) throws RequestThrottledException {
    457         throwIfCalledOnMainThread();
    458         try {
    459             VerifyCredentialResponse response =
    460                     getLockSettings().verifyTiedProfileChallenge(password,
    461                             isPattern ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_PASSWORD, challenge,
    462                             userId);
    463 
    464             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
    465                 return response.getPayload();
    466             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
    467                 throw new RequestThrottledException(response.getTimeout());
    468             } else {
    469                 return null;
    470             }
    471         } catch (RemoteException re) {
    472             return null;
    473         }
    474     }
    475 
    476     /**
    477      * Check to see if a password matches the saved password.  If no password exists,
    478      * always returns true.
    479      * @param password The password to check.
    480      * @return Whether the password matches the stored one.
    481      */
    482     public boolean checkPassword(String password, int userId) throws RequestThrottledException {
    483         return checkPassword(password, userId, null /* progressCallback */);
    484     }
    485 
    486     /**
    487      * Check to see if a password matches the saved password.  If no password exists,
    488      * always returns true.
    489      * @param password The password to check.
    490      * @return Whether the password matches the stored one.
    491      */
    492     public boolean checkPassword(String password, int userId,
    493             @Nullable CheckCredentialProgressCallback progressCallback)
    494             throws RequestThrottledException {
    495         throwIfCalledOnMainThread();
    496         return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
    497     }
    498 
    499     /**
    500      * Check to see if vold already has the password.
    501      * Note that this also clears vold's copy of the password.
    502      * @return Whether the vold password matches or not.
    503      */
    504     public boolean checkVoldPassword(int userId) {
    505         try {
    506             return getLockSettings().checkVoldPassword(userId);
    507         } catch (RemoteException re) {
    508             return false;
    509         }
    510     }
    511 
    512     /**
    513      * Returns the password history hash factor, needed to check new password against password
    514      * history with {@link #checkPasswordHistory(String, byte[], int)}
    515      */
    516     public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
    517         try {
    518             return getLockSettings().getHashFactor(currentPassword, userId);
    519         } catch (RemoteException e) {
    520             Log.e(TAG, "failed to get hash factor", e);
    521             return null;
    522         }
    523     }
    524 
    525     /**
    526      * Check to see if a password matches any of the passwords stored in the
    527      * password history.
    528      *
    529      * @param passwordToCheck The password to check.
    530      * @param hashFactor Hash factor of the current user returned from
    531      *        {@link ILockSettings#getHashFactor}
    532      * @return Whether the password matches any in the history.
    533      */
    534     public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
    535         if (TextUtils.isEmpty(passwordToCheck)) {
    536             Log.e(TAG, "checkPasswordHistory: empty password");
    537             return false;
    538         }
    539         String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
    540         if (TextUtils.isEmpty(passwordHistory)) {
    541             return false;
    542         }
    543         int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
    544         if(passwordHistoryLength == 0) {
    545             return false;
    546         }
    547         String legacyHash = legacyPasswordToHash(passwordToCheck, userId);
    548         String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId);
    549         String[] history = passwordHistory.split(HISTORY_DELIMITER);
    550         // Password History may be too long...
    551         for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) {
    552             if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) {
    553                 return true;
    554             }
    555         }
    556         return false;
    557     }
    558 
    559     /**
    560      * Check to see if the user has stored a lock pattern.
    561      * @return Whether a saved pattern exists.
    562      */
    563     private boolean savedPatternExists(int userId) {
    564         try {
    565             return getLockSettings().havePattern(userId);
    566         } catch (RemoteException re) {
    567             return false;
    568         }
    569     }
    570 
    571     /**
    572      * Check to see if the user has stored a lock pattern.
    573      * @return Whether a saved pattern exists.
    574      */
    575     private boolean savedPasswordExists(int userId) {
    576         try {
    577             return getLockSettings().havePassword(userId);
    578         } catch (RemoteException re) {
    579             return false;
    580         }
    581     }
    582 
    583     /**
    584      * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
    585      * currently cleared.
    586      *
    587      * @return True if the user has ever chosen a pattern.
    588      */
    589     public boolean isPatternEverChosen(int userId) {
    590         return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
    591     }
    592 
    593     /**
    594      * Records that the user has chosen a pattern at some time, even if the pattern is
    595      * currently cleared.
    596      */
    597     public void reportPatternWasChosen(int userId) {
    598         setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
    599     }
    600 
    601     /**
    602      * Used by device policy manager to validate the current password
    603      * information it has.
    604      */
    605     public int getActivePasswordQuality(int userId) {
    606         int quality = getKeyguardStoredPasswordQuality(userId);
    607 
    608         if (isLockPasswordEnabled(quality, userId)) {
    609             // Quality is a password and a password exists. Return the quality.
    610             return quality;
    611         }
    612 
    613         if (isLockPatternEnabled(quality, userId)) {
    614             // Quality is a pattern and a pattern exists. Return the quality.
    615             return quality;
    616         }
    617 
    618         return PASSWORD_QUALITY_UNSPECIFIED;
    619     }
    620 
    621     /**
    622      * Use it to reset keystore without wiping work profile
    623      */
    624     public void resetKeyStore(int userId) {
    625         try {
    626             getLockSettings().resetKeyStore(userId);
    627         } catch (RemoteException e) {
    628             // It should not happen
    629             Log.e(TAG, "Couldn't reset keystore " + e);
    630         }
    631     }
    632 
    633     /**
    634      * Clear any lock pattern or password.
    635      */
    636     public void clearLock(String savedCredential, int userHandle) {
    637         final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
    638         setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    639 
    640         try{
    641             getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
    642                     PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    643         } catch (Exception e) {
    644             Log.e(TAG, "Failed to clear lock", e);
    645             setKeyguardStoredPasswordQuality(currentQuality, userHandle);
    646             return;
    647         }
    648 
    649         if (userHandle == UserHandle.USER_SYSTEM) {
    650             // Set the encryption password to default.
    651             updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
    652             setCredentialRequiredToDecrypt(false);
    653         }
    654 
    655         onAfterChangingPassword(userHandle);
    656     }
    657 
    658     /**
    659      * Disable showing lock screen at all for a given user.
    660      * This is only meaningful if pattern, pin or password are not set.
    661      *
    662      * @param disable Disables lock screen when true
    663      * @param userId User ID of the user this has effect on
    664      */
    665     public void setLockScreenDisabled(boolean disable, int userId) {
    666         setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
    667     }
    668 
    669     /**
    670      * Determine if LockScreen is disabled for the current user. This is used to decide whether
    671      * LockScreen is shown after reboot or after screen timeout / short press on power.
    672      *
    673      * @return true if lock screen is disabled
    674      */
    675     public boolean isLockScreenDisabled(int userId) {
    676         if (isSecure(userId)) {
    677             return false;
    678         }
    679         boolean disabledByDefault = mContext.getResources().getBoolean(
    680                 com.android.internal.R.bool.config_disableLockscreenByDefault);
    681         boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
    682         UserInfo userInfo = getUserManager().getUserInfo(userId);
    683         boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
    684                 && userInfo.isDemo();
    685         return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
    686                 || (disabledByDefault && !isSystemUser)
    687                 || isDemoUser;
    688     }
    689 
    690     /**
    691      * Save a lock pattern.
    692      * @param pattern The new pattern to save.
    693      * @param userId the user whose pattern is to be saved.
    694      */
    695     public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
    696         this.saveLockPattern(pattern, null, userId);
    697     }
    698     /**
    699      * Save a lock pattern.
    700      * @param pattern The new pattern to save.
    701      * @param savedPattern The previously saved pattern, converted to String format
    702      * @param userId the user whose pattern is to be saved.
    703      */
    704     public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
    705         if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
    706             throw new IllegalArgumentException("pattern must not be null and at least "
    707                     + MIN_LOCK_PATTERN_SIZE + " dots long.");
    708         }
    709 
    710         final String stringPattern = patternToString(pattern);
    711         final int currentQuality = getKeyguardStoredPasswordQuality(userId);
    712         setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
    713         try {
    714             getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
    715                     savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
    716         } catch (Exception e) {
    717             Log.e(TAG, "Couldn't save lock pattern", e);
    718             setKeyguardStoredPasswordQuality(currentQuality, userId);
    719             return;
    720         }
    721         // Update the device encryption password.
    722         if (userId == UserHandle.USER_SYSTEM
    723                 && LockPatternUtils.isDeviceEncryptionEnabled()) {
    724             if (!shouldEncryptWithCredentials(true)) {
    725                 clearEncryptionPassword();
    726             } else {
    727                 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
    728             }
    729         }
    730 
    731         reportPatternWasChosen(userId);
    732         onAfterChangingPassword(userId);
    733     }
    734 
    735     private void updateCryptoUserInfo(int userId) {
    736         if (userId != UserHandle.USER_SYSTEM) {
    737             return;
    738         }
    739 
    740         final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
    741 
    742         IBinder service = ServiceManager.getService("mount");
    743         if (service == null) {
    744             Log.e(TAG, "Could not find the mount service to update the user info");
    745             return;
    746         }
    747 
    748         IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
    749         try {
    750             Log.d(TAG, "Setting owner info");
    751             storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
    752         } catch (RemoteException e) {
    753             Log.e(TAG, "Error changing user info", e);
    754         }
    755     }
    756 
    757     public void setOwnerInfo(String info, int userId) {
    758         setString(LOCK_SCREEN_OWNER_INFO, info, userId);
    759         updateCryptoUserInfo(userId);
    760     }
    761 
    762     public void setOwnerInfoEnabled(boolean enabled, int userId) {
    763         setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
    764         updateCryptoUserInfo(userId);
    765     }
    766 
    767     public String getOwnerInfo(int userId) {
    768         return getString(LOCK_SCREEN_OWNER_INFO, userId);
    769     }
    770 
    771     public boolean isOwnerInfoEnabled(int userId) {
    772         return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
    773     }
    774 
    775     /**
    776      * Sets the device owner information. If the information is {@code null} or empty then the
    777      * device owner info is cleared.
    778      *
    779      * @param info Device owner information which will be displayed instead of the user
    780      * owner info.
    781      */
    782     public void setDeviceOwnerInfo(String info) {
    783         if (info != null && info.isEmpty()) {
    784             info = null;
    785         }
    786 
    787         setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
    788     }
    789 
    790     public String getDeviceOwnerInfo() {
    791         return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
    792     }
    793 
    794     public boolean isDeviceOwnerInfoEnabled() {
    795         return getDeviceOwnerInfo() != null;
    796     }
    797 
    798     /** Update the encryption password if it is enabled **/
    799     private void updateEncryptionPassword(final int type, final String password) {
    800         if (!isDeviceEncryptionEnabled()) {
    801             return;
    802         }
    803         final IBinder service = ServiceManager.getService("mount");
    804         if (service == null) {
    805             Log.e(TAG, "Could not find the mount service to update the encryption password");
    806             return;
    807         }
    808 
    809         new AsyncTask<Void, Void, Void>() {
    810             @Override
    811             protected Void doInBackground(Void... dummy) {
    812                 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
    813                 try {
    814                     storageManager.changeEncryptionPassword(type, password);
    815                 } catch (RemoteException e) {
    816                     Log.e(TAG, "Error changing encryption password", e);
    817                 }
    818                 return null;
    819             }
    820         }.execute();
    821     }
    822 
    823     /**
    824      * Save a lock password.  Does not ensure that the password is as good
    825      * as the requested mode, but will adjust the mode to be as good as the
    826      * password.
    827      * @param password The password to save
    828      * @param savedPassword The previously saved lock password, or null if none
    829      * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    830      * @param userHandle The userId of the user to change the password for
    831      */
    832     public void saveLockPassword(String password, String savedPassword, int requestedQuality,
    833             int userHandle) {
    834         if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
    835             throw new IllegalArgumentException("password must not be null and at least "
    836                     + "of length " + MIN_LOCK_PASSWORD_SIZE);
    837         }
    838 
    839         final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
    840         setKeyguardStoredPasswordQuality(
    841                 computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
    842                 userHandle);
    843         try {
    844             getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
    845                     savedPassword, requestedQuality, userHandle);
    846         } catch (Exception e) {
    847             Log.e(TAG, "Unable to save lock password", e);
    848             setKeyguardStoredPasswordQuality(currentQuality, userHandle);
    849             return;
    850         }
    851 
    852         updateEncryptionPasswordIfNeeded(password,
    853                 PasswordMetrics.computeForPassword(password).quality, userHandle);
    854         updatePasswordHistory(password, userHandle);
    855         onAfterChangingPassword(userHandle);
    856     }
    857 
    858     /**
    859      * Update device encryption password if calling user is USER_SYSTEM and device supports
    860      * encryption.
    861      */
    862     private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
    863         // Update the device encryption password.
    864         if (userHandle == UserHandle.USER_SYSTEM
    865                 && LockPatternUtils.isDeviceEncryptionEnabled()) {
    866             if (!shouldEncryptWithCredentials(true)) {
    867                 clearEncryptionPassword();
    868             } else {
    869                 boolean numeric = quality == PASSWORD_QUALITY_NUMERIC;
    870                 boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
    871                 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
    872                         : StorageManager.CRYPT_TYPE_PASSWORD;
    873                 updateEncryptionPassword(type, password);
    874             }
    875         }
    876     }
    877 
    878     /**
    879      * Store the hash of the *current* password in the password history list, if device policy
    880      * enforces password history requirement.
    881      */
    882     private void updatePasswordHistory(String password, int userHandle) {
    883         if (TextUtils.isEmpty(password)) {
    884             Log.e(TAG, "checkPasswordHistory: empty password");
    885             return;
    886         }
    887         // Add the password to the password history. We assume all
    888         // password hashes have the same length for simplicity of implementation.
    889         String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
    890         if (passwordHistory == null) {
    891             passwordHistory = "";
    892         }
    893         int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
    894         if (passwordHistoryLength == 0) {
    895             passwordHistory = "";
    896         } else {
    897             final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle);
    898             String hash = passwordToHistoryHash(password, hashFactor, userHandle);
    899             if (hash == null) {
    900                 Log.e(TAG, "Compute new style password hash failed, fallback to legacy style");
    901                 hash = legacyPasswordToHash(password, userHandle);
    902             }
    903             if (TextUtils.isEmpty(passwordHistory)) {
    904                 passwordHistory = hash;
    905             } else {
    906                 String[] history = passwordHistory.split(HISTORY_DELIMITER);
    907                 StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER);
    908                 joiner.add(hash);
    909                 for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
    910                     joiner.add(history[i]);
    911                 }
    912                 passwordHistory = joiner.toString();
    913             }
    914         }
    915         setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
    916     }
    917 
    918     /**
    919      * Determine if the device supports encryption, even if it's set to default. This
    920      * differs from isDeviceEncrypted() in that it returns true even if the device is
    921      * encrypted with the default password.
    922      * @return true if device encryption is enabled
    923      */
    924     public static boolean isDeviceEncryptionEnabled() {
    925         return StorageManager.isEncrypted();
    926     }
    927 
    928     /**
    929      * Determine if the device is file encrypted
    930      * @return true if device is file encrypted
    931      */
    932     public static boolean isFileEncryptionEnabled() {
    933         return StorageManager.isFileEncryptedNativeOrEmulated();
    934     }
    935 
    936     /**
    937      * Clears the encryption password.
    938      */
    939     public void clearEncryptionPassword() {
    940         updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
    941     }
    942 
    943     /**
    944      * Retrieves the quality mode for {@param userHandle}.
    945      * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    946      *
    947      * @return stored password quality
    948      */
    949     public int getKeyguardStoredPasswordQuality(int userHandle) {
    950         return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    951     }
    952 
    953     private void setKeyguardStoredPasswordQuality(int quality, int userHandle) {
    954         setLong(PASSWORD_TYPE_KEY, quality, userHandle);
    955     }
    956 
    957     /**
    958      * Returns the password quality of the given credential, promoting it to a higher level
    959      * if DevicePolicyManager has a stronger quality requirement. This value will be written
    960      * to PASSWORD_TYPE_KEY.
    961      */
    962     private int computePasswordQuality(int type, String credential, int requestedQuality) {
    963         final int quality;
    964         if (type == CREDENTIAL_TYPE_PASSWORD) {
    965             int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
    966             quality = Math.max(requestedQuality, computedQuality);
    967         } else if (type == CREDENTIAL_TYPE_PATTERN)  {
    968             quality = PASSWORD_QUALITY_SOMETHING;
    969         } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
    970             quality = PASSWORD_QUALITY_UNSPECIFIED;
    971         }
    972         return quality;
    973     }
    974 
    975     /**
    976      * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
    977      * for user handles that do not belong to a managed profile.
    978      *
    979      * @param userHandle Managed profile user id
    980      * @param enabled True if separate challenge is enabled
    981      * @param managedUserPassword Managed profile previous password. Null when {@param enabled} is
    982      *            true
    983      */
    984     public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
    985             String managedUserPassword) {
    986         if (!isManagedProfile(userHandle)) {
    987             return;
    988         }
    989         try {
    990             getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
    991                     managedUserPassword);
    992             onAfterChangingPassword(userHandle);
    993         } catch (RemoteException e) {
    994             Log.e(TAG, "Couldn't update work profile challenge enabled");
    995         }
    996     }
    997 
    998     /**
    999      * Returns true if {@param userHandle} is a managed profile with separate challenge.
   1000      */
   1001     public boolean isSeparateProfileChallengeEnabled(int userHandle) {
   1002         return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
   1003     }
   1004 
   1005     /**
   1006      * Returns true if {@param userHandle} is a managed profile with unified challenge.
   1007      */
   1008     public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
   1009         return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
   1010     }
   1011 
   1012     /**
   1013      * Retrieves whether the current DPM allows use of the Profile Challenge.
   1014      */
   1015     public boolean isSeparateProfileChallengeAllowed(int userHandle) {
   1016         return isManagedProfile(userHandle)
   1017                 && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
   1018     }
   1019 
   1020     /**
   1021      * Retrieves whether the current profile and device locks can be unified.
   1022      * @param userHandle profile user handle.
   1023      */
   1024     public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
   1025         return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle)
   1026                 && !getUserManager().hasUserRestriction(
   1027                         UserManager.DISALLOW_UNIFIED_PASSWORD, UserHandle.of(userHandle));
   1028     }
   1029 
   1030     private boolean hasSeparateChallenge(int userHandle) {
   1031         try {
   1032             return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
   1033         } catch (RemoteException e) {
   1034             Log.e(TAG, "Couldn't get separate profile challenge enabled");
   1035             // Default value is false
   1036             return false;
   1037         }
   1038     }
   1039 
   1040     private boolean isManagedProfile(int userHandle) {
   1041         final UserInfo info = getUserManager().getUserInfo(userHandle);
   1042         return info != null && info.isManagedProfile();
   1043     }
   1044 
   1045     /**
   1046      * Deserialize a pattern.
   1047      * @param string The pattern serialized with {@link #patternToString}
   1048      * @return The pattern.
   1049      */
   1050     public static List<LockPatternView.Cell> stringToPattern(String string) {
   1051         if (string == null) {
   1052             return null;
   1053         }
   1054 
   1055         List<LockPatternView.Cell> result = Lists.newArrayList();
   1056 
   1057         final byte[] bytes = string.getBytes();
   1058         for (int i = 0; i < bytes.length; i++) {
   1059             byte b = (byte) (bytes[i] - '1');
   1060             result.add(LockPatternView.Cell.of(b / 3, b % 3));
   1061         }
   1062         return result;
   1063     }
   1064 
   1065     /**
   1066      * Serialize a pattern.
   1067      * @param pattern The pattern.
   1068      * @return The pattern in string form.
   1069      */
   1070     public static String patternToString(List<LockPatternView.Cell> pattern) {
   1071         if (pattern == null) {
   1072             return "";
   1073         }
   1074         final int patternSize = pattern.size();
   1075 
   1076         byte[] res = new byte[patternSize];
   1077         for (int i = 0; i < patternSize; i++) {
   1078             LockPatternView.Cell cell = pattern.get(i);
   1079             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
   1080         }
   1081         return new String(res);
   1082     }
   1083 
   1084     public static String patternStringToBaseZero(String pattern) {
   1085         if (pattern == null) {
   1086             return "";
   1087         }
   1088         final int patternSize = pattern.length();
   1089 
   1090         byte[] res = new byte[patternSize];
   1091         final byte[] bytes = pattern.getBytes();
   1092         for (int i = 0; i < patternSize; i++) {
   1093             res[i] = (byte) (bytes[i] - '1');
   1094         }
   1095         return new String(res);
   1096     }
   1097 
   1098     /*
   1099      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
   1100      * at least a second level of protection. First level is that the file
   1101      * is in a location only readable by the system process.
   1102      * @param pattern the gesture pattern.
   1103      * @return the hash of the pattern in a byte array.
   1104      */
   1105     public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
   1106         if (pattern == null) {
   1107             return null;
   1108         }
   1109 
   1110         final int patternSize = pattern.size();
   1111         byte[] res = new byte[patternSize];
   1112         for (int i = 0; i < patternSize; i++) {
   1113             LockPatternView.Cell cell = pattern.get(i);
   1114             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
   1115         }
   1116         try {
   1117             MessageDigest md = MessageDigest.getInstance("SHA-1");
   1118             byte[] hash = md.digest(res);
   1119             return hash;
   1120         } catch (NoSuchAlgorithmException nsa) {
   1121             return res;
   1122         }
   1123     }
   1124 
   1125     private String getSalt(int userId) {
   1126         long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
   1127         if (salt == 0) {
   1128             try {
   1129                 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
   1130                 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
   1131                 Log.v(TAG, "Initialized lock password salt for user: " + userId);
   1132             } catch (NoSuchAlgorithmException e) {
   1133                 // Throw an exception rather than storing a password we'll never be able to recover
   1134                 throw new IllegalStateException("Couldn't get SecureRandom number", e);
   1135             }
   1136         }
   1137         return Long.toHexString(salt);
   1138     }
   1139 
   1140     /**
   1141      * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
   1142      * Not the most secure, but it is at least a second level of protection. First level is that
   1143      * the file is in a location only readable by the system process.
   1144      *
   1145      * @param password the gesture pattern.
   1146      *
   1147      * @return the hash of the pattern in a byte array.
   1148      */
   1149     public String legacyPasswordToHash(String password, int userId) {
   1150         if (password == null) {
   1151             return null;
   1152         }
   1153 
   1154         try {
   1155             byte[] saltedPassword = (password + getSalt(userId)).getBytes();
   1156             byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
   1157             byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
   1158 
   1159             byte[] combined = new byte[sha1.length + md5.length];
   1160             System.arraycopy(sha1, 0, combined, 0, sha1.length);
   1161             System.arraycopy(md5, 0, combined, sha1.length, md5.length);
   1162 
   1163             final char[] hexEncoded = HexEncoding.encode(combined);
   1164             return new String(hexEncoded);
   1165         } catch (NoSuchAlgorithmException e) {
   1166             throw new AssertionError("Missing digest algorithm: ", e);
   1167         }
   1168     }
   1169 
   1170     /**
   1171      * Hash the password for password history check purpose.
   1172      */
   1173     private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) {
   1174         if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) {
   1175             return null;
   1176         }
   1177         try {
   1178             MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
   1179             sha256.update(hashFactor);
   1180             sha256.update((passwordToHash + getSalt(userId)).getBytes());
   1181             return new String(HexEncoding.encode(sha256.digest()));
   1182         } catch (NoSuchAlgorithmException e) {
   1183             throw new AssertionError("Missing digest algorithm: ", e);
   1184         }
   1185     }
   1186 
   1187     /**
   1188      * @param userId the user for which to report the value
   1189      * @return Whether the lock screen is secured.
   1190      */
   1191     public boolean isSecure(int userId) {
   1192         int mode = getKeyguardStoredPasswordQuality(userId);
   1193         return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
   1194     }
   1195 
   1196     public boolean isLockPasswordEnabled(int userId) {
   1197         return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
   1198     }
   1199 
   1200     private boolean isLockPasswordEnabled(int mode, int userId) {
   1201         final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC
   1202                 || mode == PASSWORD_QUALITY_NUMERIC
   1203                 || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX
   1204                 || mode == PASSWORD_QUALITY_ALPHANUMERIC
   1205                 || mode == PASSWORD_QUALITY_COMPLEX
   1206                 || mode == PASSWORD_QUALITY_MANAGED;
   1207         return passwordEnabled && savedPasswordExists(userId);
   1208     }
   1209 
   1210     /**
   1211      * @return Whether the lock pattern is enabled
   1212      */
   1213     public boolean isLockPatternEnabled(int userId) {
   1214         return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
   1215     }
   1216 
   1217     @Deprecated
   1218     public boolean isLegacyLockPatternEnabled(int userId) {
   1219         // Note: this value should default to {@code true} to avoid any reset that might result.
   1220         // We must use a special key to read this value, since it will by default return the value
   1221         // based on the new logic.
   1222         return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
   1223     }
   1224 
   1225     @Deprecated
   1226     public void setLegacyLockPatternEnabled(int userId) {
   1227         setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
   1228     }
   1229 
   1230     private boolean isLockPatternEnabled(int mode, int userId) {
   1231         return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId);
   1232     }
   1233 
   1234     /**
   1235      * @return Whether the visible pattern is enabled.
   1236      */
   1237     public boolean isVisiblePatternEnabled(int userId) {
   1238         return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
   1239     }
   1240 
   1241     /**
   1242      * Set whether the visible pattern is enabled.
   1243      */
   1244     public void setVisiblePatternEnabled(boolean enabled, int userId) {
   1245         setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
   1246 
   1247         // Update for crypto if owner
   1248         if (userId != UserHandle.USER_SYSTEM) {
   1249             return;
   1250         }
   1251 
   1252         IBinder service = ServiceManager.getService("mount");
   1253         if (service == null) {
   1254             Log.e(TAG, "Could not find the mount service to update the user info");
   1255             return;
   1256         }
   1257 
   1258         IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
   1259         try {
   1260             storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
   1261         } catch (RemoteException e) {
   1262             Log.e(TAG, "Error changing pattern visible state", e);
   1263         }
   1264     }
   1265 
   1266     public boolean isVisiblePatternEverChosen(int userId) {
   1267         return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
   1268     }
   1269 
   1270     /**
   1271      * Set whether the visible password is enabled for cryptkeeper screen.
   1272      */
   1273     public void setVisiblePasswordEnabled(boolean enabled, int userId) {
   1274         // Update for crypto if owner
   1275         if (userId != UserHandle.USER_SYSTEM) {
   1276             return;
   1277         }
   1278 
   1279         IBinder service = ServiceManager.getService("mount");
   1280         if (service == null) {
   1281             Log.e(TAG, "Could not find the mount service to update the user info");
   1282             return;
   1283         }
   1284 
   1285         IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
   1286         try {
   1287             storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
   1288         } catch (RemoteException e) {
   1289             Log.e(TAG, "Error changing password visible state", e);
   1290         }
   1291     }
   1292 
   1293     /**
   1294      * @return Whether tactile feedback for the pattern is enabled.
   1295      */
   1296     public boolean isTactileFeedbackEnabled() {
   1297         return Settings.System.getIntForUser(mContentResolver,
   1298                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
   1299     }
   1300 
   1301     /**
   1302      * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
   1303      * pattern until the deadline has passed.
   1304      * @return the chosen deadline.
   1305      */
   1306     public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
   1307         final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
   1308         if (userId == USER_FRP) {
   1309             // For secure password storage (that is required for FRP), the underlying storage also
   1310             // enforces the deadline. Since we cannot store settings for the FRP user, don't.
   1311             return deadline;
   1312         }
   1313         mLockoutDeadlines.put(userId, deadline);
   1314         return deadline;
   1315     }
   1316 
   1317     /**
   1318      * @return The elapsed time in millis in the future when the user is allowed to
   1319      *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
   1320      *   enter a pattern.
   1321      */
   1322     public long getLockoutAttemptDeadline(int userId) {
   1323         final long deadline = mLockoutDeadlines.get(userId, 0L);
   1324         final long now = SystemClock.elapsedRealtime();
   1325         if (deadline < now && deadline != 0) {
   1326             // timeout expired
   1327             mLockoutDeadlines.put(userId, 0);
   1328             return 0L;
   1329         }
   1330         return deadline;
   1331     }
   1332 
   1333     private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
   1334         try {
   1335             return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
   1336         } catch (RemoteException re) {
   1337             return defaultValue;
   1338         }
   1339     }
   1340 
   1341     private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
   1342         try {
   1343             getLockSettings().setBoolean(secureSettingKey, enabled, userId);
   1344         } catch (RemoteException re) {
   1345             // What can we do?
   1346             Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
   1347         }
   1348     }
   1349 
   1350     private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
   1351         try {
   1352             return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
   1353         } catch (RemoteException re) {
   1354             return defaultValue;
   1355         }
   1356     }
   1357 
   1358     private void setLong(String secureSettingKey, long value, int userHandle) {
   1359         try {
   1360             getLockSettings().setLong(secureSettingKey, value, userHandle);
   1361         } catch (RemoteException re) {
   1362             // What can we do?
   1363             Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
   1364         }
   1365     }
   1366 
   1367     private String getString(String secureSettingKey, int userHandle) {
   1368         try {
   1369             return getLockSettings().getString(secureSettingKey, null, userHandle);
   1370         } catch (RemoteException re) {
   1371             return null;
   1372         }
   1373     }
   1374 
   1375     private void setString(String secureSettingKey, String value, int userHandle) {
   1376         try {
   1377             getLockSettings().setString(secureSettingKey, value, userHandle);
   1378         } catch (RemoteException re) {
   1379             // What can we do?
   1380             Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
   1381         }
   1382     }
   1383 
   1384     public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
   1385         setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
   1386     }
   1387 
   1388     public boolean getPowerButtonInstantlyLocks(int userId) {
   1389         return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
   1390     }
   1391 
   1392     public boolean isPowerButtonInstantlyLocksEverChosen(int userId) {
   1393         return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
   1394     }
   1395 
   1396     public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
   1397         StringBuilder sb = new StringBuilder();
   1398         for (ComponentName cn : activeTrustAgents) {
   1399             if (sb.length() > 0) {
   1400                 sb.append(',');
   1401             }
   1402             sb.append(cn.flattenToShortString());
   1403         }
   1404         setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
   1405         getTrustManager().reportEnabledTrustAgentsChanged(userId);
   1406     }
   1407 
   1408     public List<ComponentName> getEnabledTrustAgents(int userId) {
   1409         String serialized = getString(ENABLED_TRUST_AGENTS, userId);
   1410         if (TextUtils.isEmpty(serialized)) {
   1411             return null;
   1412         }
   1413         String[] split = serialized.split(",");
   1414         ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
   1415         for (String s : split) {
   1416             if (!TextUtils.isEmpty(s)) {
   1417                 activeTrustAgents.add(ComponentName.unflattenFromString(s));
   1418             }
   1419         }
   1420         return activeTrustAgents;
   1421     }
   1422 
   1423     /**
   1424      * Disable trust until credentials have been entered for user {@param userId}.
   1425      *
   1426      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
   1427      *
   1428      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
   1429      */
   1430     public void requireCredentialEntry(int userId) {
   1431         requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
   1432     }
   1433 
   1434     /**
   1435      * Requests strong authentication for user {@param userId}.
   1436      *
   1437      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
   1438      *
   1439      * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
   1440      *                         the reason for and the strength of the requested authentication.
   1441      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
   1442      */
   1443     public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
   1444             int userId) {
   1445         try {
   1446             getLockSettings().requireStrongAuth(strongAuthReason, userId);
   1447         } catch (RemoteException e) {
   1448             Log.e(TAG, "Error while requesting strong auth: " + e);
   1449         }
   1450     }
   1451 
   1452     private void onAfterChangingPassword(int userHandle) {
   1453         getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
   1454     }
   1455 
   1456     public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
   1457         final int value = Settings.Global.getInt(mContentResolver,
   1458                 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
   1459         return value == -1 ? defaultValue : (value != 0);
   1460     }
   1461 
   1462     public void setCredentialRequiredToDecrypt(boolean required) {
   1463         if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
   1464             throw new IllegalStateException(
   1465                     "Only the system or primary user may call setCredentialRequiredForDecrypt()");
   1466         }
   1467 
   1468         if (isDeviceEncryptionEnabled()){
   1469             Settings.Global.putInt(mContext.getContentResolver(),
   1470                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
   1471         }
   1472     }
   1473 
   1474     private boolean isDoNotAskCredentialsOnBootSet() {
   1475         return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
   1476     }
   1477 
   1478     private boolean shouldEncryptWithCredentials(boolean defaultValue) {
   1479         return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
   1480     }
   1481 
   1482     private void throwIfCalledOnMainThread() {
   1483         if (Looper.getMainLooper().isCurrentThread()) {
   1484             throw new IllegalStateException("should not be called from the main thread.");
   1485         }
   1486     }
   1487 
   1488     public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
   1489         try {
   1490             getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
   1491         } catch (RemoteException e) {
   1492             throw new RuntimeException("Could not register StrongAuthTracker");
   1493         }
   1494     }
   1495 
   1496     public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
   1497         try {
   1498             getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
   1499         } catch (RemoteException e) {
   1500             Log.e(TAG, "Could not unregister StrongAuthTracker", e);
   1501         }
   1502     }
   1503 
   1504     /**
   1505      * @see StrongAuthTracker#getStrongAuthForUser
   1506      */
   1507     public int getStrongAuthForUser(int userId) {
   1508         try {
   1509             return getLockSettings().getStrongAuthForUser(userId);
   1510         } catch (RemoteException e) {
   1511             Log.e(TAG, "Could not get StrongAuth", e);
   1512             return StrongAuthTracker.getDefaultFlags(mContext);
   1513         }
   1514     }
   1515 
   1516     /**
   1517      * @see StrongAuthTracker#isTrustAllowedForUser
   1518      */
   1519     public boolean isTrustAllowedForUser(int userId) {
   1520         return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
   1521     }
   1522 
   1523     /**
   1524      * @see StrongAuthTracker#isFingerprintAllowedForUser
   1525      */
   1526     public boolean isFingerprintAllowedForUser(int userId) {
   1527         return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
   1528     }
   1529 
   1530     public boolean isUserInLockdown(int userId) {
   1531         return getStrongAuthForUser(userId)
   1532                 == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
   1533     }
   1534 
   1535     private ICheckCredentialProgressCallback wrapCallback(
   1536             final CheckCredentialProgressCallback callback) {
   1537         if (callback == null) {
   1538             return null;
   1539         } else {
   1540             if (mHandler == null) {
   1541                 throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
   1542                         + " to use progress callbacks.");
   1543             }
   1544             return new ICheckCredentialProgressCallback.Stub() {
   1545 
   1546                 @Override
   1547                 public void onCredentialVerified() throws RemoteException {
   1548                     mHandler.post(callback::onEarlyMatched);
   1549                 }
   1550             };
   1551         }
   1552     }
   1553 
   1554     private LockSettingsInternal getLockSettingsInternal() {
   1555         LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
   1556         if (service == null) {
   1557             throw new SecurityException("Only available to system server itself");
   1558         }
   1559         return service;
   1560     }
   1561     /**
   1562      * Create an escrow token for the current user, which can later be used to unlock FBE
   1563      * or change user password.
   1564      *
   1565      * After adding, if the user currently has lockscreen password, he will need to perform a
   1566      * confirm credential operation in order to activate the token for future use. If the user
   1567      * has no secure lockscreen, then the token is activated immediately.
   1568      *
   1569      * <p>This method is only available to code running in the system server process itself.
   1570      *
   1571      * @return a unique 64-bit token handle which is needed to refer to this token later.
   1572      */
   1573     public long addEscrowToken(byte[] token, int userId) {
   1574         return getLockSettingsInternal().addEscrowToken(token, userId);
   1575     }
   1576 
   1577     /**
   1578      * Remove an escrow token.
   1579      *
   1580      * <p>This method is only available to code running in the system server process itself.
   1581      *
   1582      * @return true if the given handle refers to a valid token previously returned from
   1583      * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
   1584      */
   1585     public boolean removeEscrowToken(long handle, int userId) {
   1586         return getLockSettingsInternal().removeEscrowToken(handle, userId);
   1587     }
   1588 
   1589     /**
   1590      * Check if the given escrow token is active or not. Only active token can be used to call
   1591      * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
   1592      *
   1593      * <p>This method is only available to code running in the system server process itself.
   1594      */
   1595     public boolean isEscrowTokenActive(long handle, int userId) {
   1596         return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
   1597     }
   1598 
   1599     /**
   1600      * Change a user's lock credential with a pre-configured escrow token.
   1601      *
   1602      * <p>This method is only available to code running in the system server process itself.
   1603      *
   1604      * @param credential The new credential to be set
   1605      * @param type Credential type: password / pattern / none.
   1606      * @param requestedQuality the requested password quality by DevicePolicyManager.
   1607      *        See {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
   1608      * @param tokenHandle Handle of the escrow token
   1609      * @param token Escrow token
   1610      * @param userId The user who's lock credential to be changed
   1611      * @return {@code true} if the operation is successful.
   1612      */
   1613     public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
   1614             long tokenHandle, byte[] token, int userId) {
   1615         LockSettingsInternal localService = getLockSettingsInternal();
   1616         if (type != CREDENTIAL_TYPE_NONE) {
   1617             if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
   1618                 throw new IllegalArgumentException("password must not be null and at least "
   1619                         + "of length " + MIN_LOCK_PASSWORD_SIZE);
   1620             }
   1621             final int quality = computePasswordQuality(type, credential, requestedQuality);
   1622             if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
   1623                     token, quality, userId)) {
   1624                 return false;
   1625             }
   1626             setKeyguardStoredPasswordQuality(quality, userId);
   1627 
   1628             updateEncryptionPasswordIfNeeded(credential, quality, userId);
   1629             updatePasswordHistory(credential, userId);
   1630             onAfterChangingPassword(userId);
   1631         } else {
   1632             if (!TextUtils.isEmpty(credential)) {
   1633                 throw new IllegalArgumentException("password must be emtpy for NONE type");
   1634             }
   1635             if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
   1636                     tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
   1637                 return false;
   1638             }
   1639             setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
   1640 
   1641             if (userId == UserHandle.USER_SYSTEM) {
   1642                 // Set the encryption password to default.
   1643                 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
   1644                 setCredentialRequiredToDecrypt(false);
   1645             }
   1646         }
   1647         onAfterChangingPassword(userId);
   1648         return true;
   1649     }
   1650 
   1651     /**
   1652      * Unlock the specified user by an pre-activated escrow token. This should have the same effect
   1653      * on device encryption as the user entering his lockscreen credentials for the first time after
   1654      * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
   1655      *
   1656      * <p>This method is only available to code running in the system server process itself.
   1657      *
   1658      * @return {@code true} if the supplied token is valid and unlock succeeds,
   1659      *         {@code false} otherwise.
   1660      */
   1661     public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
   1662         return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
   1663     }
   1664 
   1665 
   1666     /**
   1667      * Callback to be notified about progress when checking credentials.
   1668      */
   1669     public interface CheckCredentialProgressCallback {
   1670 
   1671         /**
   1672          * Called as soon as possible when we know that the credentials match but the user hasn't
   1673          * been fully unlocked.
   1674          */
   1675         void onEarlyMatched();
   1676     }
   1677 
   1678     /**
   1679      * Tracks the global strong authentication state.
   1680      */
   1681     public static class StrongAuthTracker {
   1682 
   1683         @IntDef(flag = true,
   1684                 value = { STRONG_AUTH_NOT_REQUIRED,
   1685                         STRONG_AUTH_REQUIRED_AFTER_BOOT,
   1686                         STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
   1687                         SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
   1688                         STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
   1689                         STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
   1690                         STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
   1691         @Retention(RetentionPolicy.SOURCE)
   1692         public @interface StrongAuthFlags {}
   1693 
   1694         /**
   1695          * Strong authentication is not required.
   1696          */
   1697         public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
   1698 
   1699         /**
   1700          * Strong authentication is required because the user has not authenticated since boot.
   1701          */
   1702         public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
   1703 
   1704         /**
   1705          * Strong authentication is required because a device admin has requested it.
   1706          */
   1707         public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
   1708 
   1709         /**
   1710          * Some authentication is required because the user has temporarily disabled trust.
   1711          */
   1712         public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
   1713 
   1714         /**
   1715          * Strong authentication is required because the user has been locked out after too many
   1716          * attempts.
   1717          */
   1718         public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
   1719 
   1720         /**
   1721          * Strong authentication is required because it hasn't been used for a time required by
   1722          * a device admin.
   1723          */
   1724         public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
   1725 
   1726         /**
   1727          * Strong authentication is required because the user has triggered lockdown.
   1728          */
   1729         public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
   1730 
   1731         /**
   1732          * Strong auth flags that do not prevent fingerprint from being accepted as auth.
   1733          *
   1734          * If any other flags are set, fingerprint is disabled.
   1735          */
   1736         private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
   1737                 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
   1738 
   1739         private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
   1740         private final H mHandler;
   1741         private final int mDefaultStrongAuthFlags;
   1742 
   1743         public StrongAuthTracker(Context context) {
   1744             this(context, Looper.myLooper());
   1745         }
   1746 
   1747         /**
   1748          * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
   1749          *               will be scheduled.
   1750          * @param context the current {@link Context}
   1751          */
   1752         public StrongAuthTracker(Context context, Looper looper) {
   1753             mHandler = new H(looper);
   1754             mDefaultStrongAuthFlags = getDefaultFlags(context);
   1755         }
   1756 
   1757         public static @StrongAuthFlags int getDefaultFlags(Context context) {
   1758             boolean strongAuthRequired = context.getResources().getBoolean(
   1759                     com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
   1760             return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
   1761         }
   1762 
   1763         /**
   1764          * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
   1765          * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
   1766          * authentication is required.
   1767          *
   1768          * @param userId the user for whom the state is queried.
   1769          */
   1770         public @StrongAuthFlags int getStrongAuthForUser(int userId) {
   1771             return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
   1772         }
   1773 
   1774         /**
   1775          * @return true if unlocking with trust alone is allowed for {@param userId} by the current
   1776          * strong authentication requirements.
   1777          */
   1778         public boolean isTrustAllowedForUser(int userId) {
   1779             return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
   1780         }
   1781 
   1782         /**
   1783          * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
   1784          * current strong authentication requirements.
   1785          */
   1786         public boolean isFingerprintAllowedForUser(int userId) {
   1787             return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
   1788         }
   1789 
   1790         /**
   1791          * Called when the strong authentication requirements for {@param userId} changed.
   1792          */
   1793         public void onStrongAuthRequiredChanged(int userId) {
   1794         }
   1795 
   1796         protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
   1797                 int userId) {
   1798             int oldValue = getStrongAuthForUser(userId);
   1799             if (strongAuthFlags != oldValue) {
   1800                 if (strongAuthFlags == mDefaultStrongAuthFlags) {
   1801                     mStrongAuthRequiredForUser.delete(userId);
   1802                 } else {
   1803                     mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
   1804                 }
   1805                 onStrongAuthRequiredChanged(userId);
   1806             }
   1807         }
   1808 
   1809 
   1810         protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
   1811             @Override
   1812             public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
   1813                     int userId) {
   1814                 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
   1815                         strongAuthFlags, userId).sendToTarget();
   1816             }
   1817         };
   1818 
   1819         private class H extends Handler {
   1820             static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
   1821 
   1822             public H(Looper looper) {
   1823                 super(looper);
   1824             }
   1825 
   1826             @Override
   1827             public void handleMessage(Message msg) {
   1828                 switch (msg.what) {
   1829                     case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
   1830                         handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
   1831                         break;
   1832                 }
   1833             }
   1834         }
   1835     }
   1836 
   1837     public void enableSyntheticPassword() {
   1838         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1L, UserHandle.USER_SYSTEM);
   1839     }
   1840 
   1841     public void disableSyntheticPassword() {
   1842         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0L, UserHandle.USER_SYSTEM);
   1843     }
   1844 
   1845     public boolean isSyntheticPasswordEnabled() {
   1846         return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
   1847     }
   1848 
   1849     public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
   1850         return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
   1851     }
   1852 
   1853     public static boolean frpCredentialEnabled(Context context) {
   1854         return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
   1855                 com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
   1856     }
   1857 }
   1858