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