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