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