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.Manifest;
     20 import android.app.ActivityManagerNative;
     21 import android.app.AlarmManager;
     22 import android.app.admin.DevicePolicyManager;
     23 import android.app.trust.TrustManager;
     24 import android.appwidget.AppWidgetManager;
     25 import android.content.ComponentName;
     26 import android.content.ContentResolver;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.pm.PackageManager;
     30 import android.content.pm.UserInfo;
     31 import android.os.AsyncTask;
     32 import android.os.IBinder;
     33 import android.os.RemoteException;
     34 import android.os.ServiceManager;
     35 import android.os.SystemClock;
     36 import android.os.SystemProperties;
     37 import android.os.UserHandle;
     38 import android.os.UserManager;
     39 import android.os.storage.IMountService;
     40 import android.os.storage.StorageManager;
     41 import android.provider.Settings;
     42 import android.telecom.TelecomManager;
     43 import android.text.TextUtils;
     44 import android.util.Log;
     45 import android.view.IWindowManager;
     46 import android.view.View;
     47 import android.widget.Button;
     48 
     49 import com.android.internal.R;
     50 import com.google.android.collect.Lists;
     51 
     52 import java.security.MessageDigest;
     53 import java.security.NoSuchAlgorithmException;
     54 import java.security.SecureRandom;
     55 import java.util.ArrayList;
     56 import java.util.Collection;
     57 import java.util.List;
     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 maximum number of incorrect attempts before the user is prevented
     69      * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
     70      */
     71     public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
     72 
     73     /**
     74      * The number of incorrect attempts before which we fall back on an alternative
     75      * method of verifying the user, and resetting their lock pattern.
     76      */
     77     public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
     78 
     79     /**
     80      * How long the user is prevented from trying again after entering the
     81      * wrong pattern too many times.
     82      */
     83     public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
     84 
     85     /**
     86      * The interval of the countdown for showing progress of the lockout.
     87      */
     88     public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
     89 
     90 
     91     /**
     92      * This dictates when we start telling the user that continued failed attempts will wipe
     93      * their device.
     94      */
     95     public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
     96 
     97     /**
     98      * The minimum number of dots in a valid pattern.
     99      */
    100     public static final int MIN_LOCK_PATTERN_SIZE = 4;
    101 
    102     /**
    103      * The minimum number of dots the user must include in a wrong pattern
    104      * attempt for it to be counted against the counts that affect
    105      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
    106      */
    107     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
    108 
    109     /**
    110      * Tells the keyguard to show the user switcher when the keyguard is created.
    111      */
    112     public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
    113 
    114     /**
    115      * Tells the keyguard to show the security challenge when the keyguard is created.
    116      */
    117     public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
    118 
    119     /**
    120      * Tells the keyguard to show the widget with the specified id when the keyguard is created.
    121      */
    122     public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
    123 
    124     /**
    125      * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
    126      * be used
    127      */
    128     public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
    129 
    130     /**
    131      * Pseudo-appwidget id we use to represent the default clock status widget
    132      */
    133     public static final int ID_DEFAULT_STATUS_WIDGET = -2;
    134 
    135     public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
    136     public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
    137     public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
    138     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
    139     public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
    140     public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
    141     public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
    142     public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
    143     public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
    144             = "lockscreen.biometric_weak_fallback";
    145     public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
    146             = "lockscreen.biometricweakeverchosen";
    147     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
    148             = "lockscreen.power_button_instantly_locks";
    149     public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
    150 
    151     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
    152 
    153     private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
    154     private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
    155             Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    156 
    157     private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
    158 
    159     // Maximum allowed number of repeated or ordered characters in a sequence before we'll
    160     // consider it a complex PIN/password.
    161     public static final int MAX_ALLOWED_SEQUENCE = 3;
    162 
    163     private final Context mContext;
    164     private final ContentResolver mContentResolver;
    165     private DevicePolicyManager mDevicePolicyManager;
    166     private ILockSettings mLockSettingsService;
    167 
    168     private final boolean mMultiUserMode;
    169 
    170     // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
    171     private static volatile int sCurrentUserId = UserHandle.USER_NULL;
    172 
    173     public DevicePolicyManager getDevicePolicyManager() {
    174         if (mDevicePolicyManager == null) {
    175             mDevicePolicyManager =
    176                 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    177             if (mDevicePolicyManager == null) {
    178                 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
    179                         new IllegalStateException("Stack trace:"));
    180             }
    181         }
    182         return mDevicePolicyManager;
    183     }
    184 
    185     private TrustManager getTrustManager() {
    186         TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
    187         if (trust == null) {
    188             Log.e(TAG, "Can't get TrustManagerService: is it running?",
    189                     new IllegalStateException("Stack trace:"));
    190         }
    191         return trust;
    192     }
    193 
    194     public LockPatternUtils(Context context) {
    195         mContext = context;
    196         mContentResolver = context.getContentResolver();
    197 
    198         // If this is being called by the system or by an application like keyguard that
    199         // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
    200         // mode where calls are for the current user rather than the user of the calling process.
    201         mMultiUserMode = context.checkCallingOrSelfPermission(
    202             Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
    203     }
    204 
    205     private ILockSettings getLockSettings() {
    206         if (mLockSettingsService == null) {
    207             ILockSettings service = ILockSettings.Stub.asInterface(
    208                     ServiceManager.getService("lock_settings"));
    209             mLockSettingsService = service;
    210         }
    211         return mLockSettingsService;
    212     }
    213 
    214     public int getRequestedMinimumPasswordLength() {
    215         return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
    216     }
    217 
    218     /**
    219      * Gets the device policy password mode. If the mode is non-specific, returns
    220      * MODE_PATTERN which allows the user to choose anything.
    221      */
    222     public int getRequestedPasswordQuality() {
    223         return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
    224     }
    225 
    226     public int getRequestedPasswordHistoryLength() {
    227         return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
    228     }
    229 
    230     public int getRequestedPasswordMinimumLetters() {
    231         return getDevicePolicyManager().getPasswordMinimumLetters(null,
    232                 getCurrentOrCallingUserId());
    233     }
    234 
    235     public int getRequestedPasswordMinimumUpperCase() {
    236         return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
    237                 getCurrentOrCallingUserId());
    238     }
    239 
    240     public int getRequestedPasswordMinimumLowerCase() {
    241         return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
    242                 getCurrentOrCallingUserId());
    243     }
    244 
    245     public int getRequestedPasswordMinimumNumeric() {
    246         return getDevicePolicyManager().getPasswordMinimumNumeric(null,
    247                 getCurrentOrCallingUserId());
    248     }
    249 
    250     public int getRequestedPasswordMinimumSymbols() {
    251         return getDevicePolicyManager().getPasswordMinimumSymbols(null,
    252                 getCurrentOrCallingUserId());
    253     }
    254 
    255     public int getRequestedPasswordMinimumNonLetter() {
    256         return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
    257                 getCurrentOrCallingUserId());
    258     }
    259 
    260     public void reportFailedPasswordAttempt() {
    261         int userId = getCurrentOrCallingUserId();
    262         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
    263         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
    264         getTrustManager().reportRequireCredentialEntry(userId);
    265     }
    266 
    267     public void reportSuccessfulPasswordAttempt() {
    268         getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
    269         getTrustManager().reportUnlockAttempt(true /* authenticated */,
    270                 getCurrentOrCallingUserId());
    271     }
    272 
    273     public void setCurrentUser(int userId) {
    274         sCurrentUserId = userId;
    275     }
    276 
    277     public int getCurrentUser() {
    278         if (sCurrentUserId != UserHandle.USER_NULL) {
    279             // Someone is regularly updating using setCurrentUser() use that value.
    280             return sCurrentUserId;
    281         }
    282         try {
    283             return ActivityManagerNative.getDefault().getCurrentUser().id;
    284         } catch (RemoteException re) {
    285             return UserHandle.USER_OWNER;
    286         }
    287     }
    288 
    289     public void removeUser(int userId) {
    290         try {
    291             getLockSettings().removeUser(userId);
    292         } catch (RemoteException re) {
    293             Log.e(TAG, "Couldn't remove lock settings for user " + userId);
    294         }
    295     }
    296 
    297     private int getCurrentOrCallingUserId() {
    298         if (mMultiUserMode) {
    299             // TODO: This is a little inefficient. See if all users of this are able to
    300             // handle USER_CURRENT and pass that instead.
    301             return getCurrentUser();
    302         } else {
    303             return UserHandle.getCallingUserId();
    304         }
    305     }
    306 
    307     /**
    308      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
    309      * always returns true.
    310      * @param pattern The pattern to check.
    311      * @return Whether the pattern matches the stored one.
    312      */
    313     public boolean checkPattern(List<LockPatternView.Cell> pattern) {
    314         final int userId = getCurrentOrCallingUserId();
    315         try {
    316             return getLockSettings().checkPattern(patternToString(pattern), userId);
    317         } catch (RemoteException re) {
    318             return true;
    319         }
    320     }
    321 
    322     /**
    323      * Check to see if a password matches the saved password.  If no password exists,
    324      * always returns true.
    325      * @param password The password to check.
    326      * @return Whether the password matches the stored one.
    327      */
    328     public boolean checkPassword(String password) {
    329         final int userId = getCurrentOrCallingUserId();
    330         try {
    331             return getLockSettings().checkPassword(password, userId);
    332         } catch (RemoteException re) {
    333             return true;
    334         }
    335     }
    336 
    337     /**
    338      * Check to see if vold already has the password.
    339      * Note that this also clears vold's copy of the password.
    340      * @return Whether the vold password matches or not.
    341      */
    342     public boolean checkVoldPassword() {
    343         final int userId = getCurrentOrCallingUserId();
    344         try {
    345             return getLockSettings().checkVoldPassword(userId);
    346         } catch (RemoteException re) {
    347             return false;
    348         }
    349     }
    350 
    351     /**
    352      * Check to see if a password matches any of the passwords stored in the
    353      * password history.
    354      *
    355      * @param password The password to check.
    356      * @return Whether the password matches any in the history.
    357      */
    358     public boolean checkPasswordHistory(String password) {
    359         String passwordHashString = new String(
    360                 passwordToHash(password, getCurrentOrCallingUserId()));
    361         String passwordHistory = getString(PASSWORD_HISTORY_KEY);
    362         if (passwordHistory == null) {
    363             return false;
    364         }
    365         // Password History may be too long...
    366         int passwordHashLength = passwordHashString.length();
    367         int passwordHistoryLength = getRequestedPasswordHistoryLength();
    368         if(passwordHistoryLength == 0) {
    369             return false;
    370         }
    371         int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
    372                 + passwordHistoryLength - 1;
    373         if (passwordHistory.length() > neededPasswordHistoryLength) {
    374             passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
    375         }
    376         return passwordHistory.contains(passwordHashString);
    377     }
    378 
    379     /**
    380      * Check to see if the user has stored a lock pattern.
    381      * @return Whether a saved pattern exists.
    382      */
    383     public boolean savedPatternExists() {
    384         return savedPatternExists(getCurrentOrCallingUserId());
    385     }
    386 
    387     /**
    388      * Check to see if the user has stored a lock pattern.
    389      * @return Whether a saved pattern exists.
    390      */
    391     public boolean savedPatternExists(int userId) {
    392         try {
    393             return getLockSettings().havePattern(userId);
    394         } catch (RemoteException re) {
    395             return false;
    396         }
    397     }
    398 
    399     /**
    400      * Check to see if the user has stored a lock pattern.
    401      * @return Whether a saved pattern exists.
    402      */
    403     public boolean savedPasswordExists() {
    404         return savedPasswordExists(getCurrentOrCallingUserId());
    405     }
    406 
    407      /**
    408      * Check to see if the user has stored a lock pattern.
    409      * @return Whether a saved pattern exists.
    410      */
    411     public boolean savedPasswordExists(int userId) {
    412         try {
    413             return getLockSettings().havePassword(userId);
    414         } catch (RemoteException re) {
    415             return false;
    416         }
    417     }
    418 
    419     /**
    420      * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
    421      * currently cleared.
    422      *
    423      * @return True if the user has ever chosen a pattern.
    424      */
    425     public boolean isPatternEverChosen() {
    426         return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
    427     }
    428 
    429     /**
    430      * Return true if the user has ever chosen biometric weak.  This is true even if biometric
    431      * weak is not current set.
    432      *
    433      * @return True if the user has ever chosen biometric weak.
    434      */
    435     public boolean isBiometricWeakEverChosen() {
    436         return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
    437     }
    438 
    439     /**
    440      * Used by device policy manager to validate the current password
    441      * information it has.
    442      */
    443     public int getActivePasswordQuality() {
    444         int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    445         // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
    446         // return biometric_weak if that is being used instead of the backup
    447         int quality =
    448                 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    449         switch (quality) {
    450             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
    451                 if (isLockPatternEnabled()) {
    452                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
    453                 }
    454                 break;
    455             case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
    456                 if (isBiometricWeakInstalled()) {
    457                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
    458                 }
    459                 break;
    460             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
    461                 if (isLockPasswordEnabled()) {
    462                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
    463                 }
    464                 break;
    465             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
    466                 if (isLockPasswordEnabled()) {
    467                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
    468                 }
    469                 break;
    470             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
    471                 if (isLockPasswordEnabled()) {
    472                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
    473                 }
    474                 break;
    475             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
    476                 if (isLockPasswordEnabled()) {
    477                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
    478                 }
    479                 break;
    480             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
    481                 if (isLockPasswordEnabled()) {
    482                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
    483                 }
    484                 break;
    485         }
    486 
    487         return activePasswordQuality;
    488     }
    489 
    490     public void clearLock(boolean isFallback) {
    491         clearLock(isFallback, getCurrentOrCallingUserId());
    492     }
    493 
    494     /**
    495      * Clear any lock pattern or password.
    496      */
    497     public void clearLock(boolean isFallback, int userHandle) {
    498         if(!isFallback) deleteGallery(userHandle);
    499         saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, isFallback,
    500                 userHandle);
    501         setLockPatternEnabled(false, userHandle);
    502         saveLockPattern(null, isFallback, userHandle);
    503         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    504         setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    505                 userHandle);
    506         onAfterChangingPassword(userHandle);
    507     }
    508 
    509     /**
    510      * Disable showing lock screen at all when the DevicePolicyManager allows it.
    511      * This is only meaningful if pattern, pin or password are not set.
    512      *
    513      * @param disable Disables lock screen when true
    514      */
    515     public void setLockScreenDisabled(boolean disable) {
    516         setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
    517     }
    518 
    519     /**
    520      * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
    521      * show LockScreen or go straight to the home screen.
    522      *
    523      * @return true if lock screen is can be disabled
    524      */
    525     public boolean isLockScreenDisabled() {
    526         if (!isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0) {
    527             // Check if the number of switchable users forces the lockscreen.
    528             final List<UserInfo> users = UserManager.get(mContext).getUsers(true);
    529             final int userCount = users.size();
    530             int switchableUsers = 0;
    531             for (int i = 0; i < userCount; i++) {
    532                 if (users.get(i).supportsSwitchTo()) {
    533                     switchableUsers++;
    534                 }
    535             }
    536             return switchableUsers < 2;
    537         }
    538         return false;
    539     }
    540 
    541     /**
    542      * Calls back SetupFaceLock to delete the temporary gallery file
    543      */
    544     public void deleteTempGallery() {
    545         Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
    546         intent.putExtra("deleteTempGallery", true);
    547         mContext.sendBroadcast(intent);
    548     }
    549 
    550     /**
    551      * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
    552     */
    553     void deleteGallery(int userId) {
    554         if(usingBiometricWeak(userId)) {
    555             Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
    556             intent.putExtra("deleteGallery", true);
    557             mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
    558         }
    559     }
    560 
    561     /**
    562      * Save a lock pattern.
    563      * @param pattern The new pattern to save.
    564      */
    565     public void saveLockPattern(List<LockPatternView.Cell> pattern) {
    566         this.saveLockPattern(pattern, false);
    567     }
    568 
    569     /**
    570      * Save a lock pattern.
    571      * @param pattern The new pattern to save.
    572      */
    573     public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
    574         this.saveLockPattern(pattern, isFallback, getCurrentOrCallingUserId());
    575     }
    576 
    577     /**
    578      * Save a lock pattern.
    579      * @param pattern The new pattern to save.
    580      * @param isFallback Specifies if this is a fallback to biometric weak
    581      * @param userId the user whose pattern is to be saved.
    582      */
    583     public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback,
    584             int userId) {
    585         try {
    586             getLockSettings().setLockPattern(patternToString(pattern), userId);
    587             DevicePolicyManager dpm = getDevicePolicyManager();
    588             if (pattern != null) {
    589                 // Update the device encryption password.
    590                 if (userId == UserHandle.USER_OWNER
    591                         && LockPatternUtils.isDeviceEncryptionEnabled()) {
    592                     final boolean required = isCredentialRequiredToDecrypt(true);
    593                     if (!required) {
    594                         clearEncryptionPassword();
    595                     } else {
    596                         String stringPattern = patternToString(pattern);
    597                         updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
    598                     }
    599                 }
    600 
    601                 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
    602                 if (!isFallback) {
    603                     deleteGallery(userId);
    604                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
    605                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
    606                             pattern.size(), 0, 0, 0, 0, 0, 0, userId);
    607                 } else {
    608                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, userId);
    609                     setLong(PASSWORD_TYPE_ALTERNATE_KEY,
    610                             DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
    611                     finishBiometricWeak(userId);
    612                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
    613                             0, 0, 0, 0, 0, 0, 0, userId);
    614                 }
    615             } else {
    616                 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
    617                         0, 0, 0, 0, 0, userId);
    618             }
    619             onAfterChangingPassword(userId);
    620         } catch (RemoteException re) {
    621             Log.e(TAG, "Couldn't save lock pattern " + re);
    622         }
    623     }
    624 
    625     private void updateCryptoUserInfo() {
    626         int userId = getCurrentOrCallingUserId();
    627         if (userId != UserHandle.USER_OWNER) {
    628             return;
    629         }
    630 
    631         final String ownerInfo = isOwnerInfoEnabled() ? getOwnerInfo(userId) : "";
    632 
    633         IBinder service = ServiceManager.getService("mount");
    634         if (service == null) {
    635             Log.e(TAG, "Could not find the mount service to update the user info");
    636             return;
    637         }
    638 
    639         IMountService mountService = IMountService.Stub.asInterface(service);
    640         try {
    641             Log.d(TAG, "Setting owner info");
    642             mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
    643         } catch (RemoteException e) {
    644             Log.e(TAG, "Error changing user info", e);
    645         }
    646     }
    647 
    648     public void setOwnerInfo(String info, int userId) {
    649         setString(LOCK_SCREEN_OWNER_INFO, info, userId);
    650         updateCryptoUserInfo();
    651     }
    652 
    653     public void setOwnerInfoEnabled(boolean enabled) {
    654         setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
    655         updateCryptoUserInfo();
    656     }
    657 
    658     public String getOwnerInfo(int userId) {
    659         return getString(LOCK_SCREEN_OWNER_INFO);
    660     }
    661 
    662     public boolean isOwnerInfoEnabled() {
    663         return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
    664     }
    665 
    666     /**
    667      * Compute the password quality from the given password string.
    668      */
    669     static public int computePasswordQuality(String password) {
    670         boolean hasDigit = false;
    671         boolean hasNonDigit = false;
    672         final int len = password.length();
    673         for (int i = 0; i < len; i++) {
    674             if (Character.isDigit(password.charAt(i))) {
    675                 hasDigit = true;
    676             } else {
    677                 hasNonDigit = true;
    678             }
    679         }
    680 
    681         if (hasNonDigit && hasDigit) {
    682             return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
    683         }
    684         if (hasNonDigit) {
    685             return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
    686         }
    687         if (hasDigit) {
    688             return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
    689                     ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
    690                     : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
    691         }
    692         return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    693     }
    694 
    695     private static int categoryChar(char c) {
    696         if ('a' <= c && c <= 'z') return 0;
    697         if ('A' <= c && c <= 'Z') return 1;
    698         if ('0' <= c && c <= '9') return 2;
    699         return 3;
    700     }
    701 
    702     private static int maxDiffCategory(int category) {
    703         if (category == 0 || category == 1) return 1;
    704         else if (category == 2) return 10;
    705         return 0;
    706     }
    707 
    708     /*
    709      * Returns the maximum length of a sequential characters.  A sequence is defined as
    710      * monotonically increasing characters with a constant interval or the same character repeated.
    711      *
    712      * For example:
    713      * maxLengthSequence("1234") == 4
    714      * maxLengthSequence("1234abc") == 4
    715      * maxLengthSequence("aabc") == 3
    716      * maxLengthSequence("qwertyuio") == 1
    717      * maxLengthSequence("@ABC") == 3
    718      * maxLengthSequence(";;;;") == 4 (anything that repeats)
    719      * maxLengthSequence(":;<=>") == 1  (ordered, but not composed of alphas or digits)
    720      *
    721      * @param string the pass
    722      * @return the number of sequential letters or digits
    723      */
    724     public static int maxLengthSequence(String string) {
    725         if (string.length() == 0) return 0;
    726         char previousChar = string.charAt(0);
    727         int category = categoryChar(previousChar); //current category of the sequence
    728         int diff = 0; //difference between two consecutive characters
    729         boolean hasDiff = false; //if we are currently targeting a sequence
    730         int maxLength = 0; //maximum length of a sequence already found
    731         int startSequence = 0; //where the current sequence started
    732         for (int current = 1; current < string.length(); current++) {
    733             char currentChar = string.charAt(current);
    734             int categoryCurrent = categoryChar(currentChar);
    735             int currentDiff = (int) currentChar - (int) previousChar;
    736             if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
    737                 maxLength = Math.max(maxLength, current - startSequence);
    738                 startSequence = current;
    739                 hasDiff = false;
    740                 category = categoryCurrent;
    741             }
    742             else {
    743                 if(hasDiff && currentDiff != diff) {
    744                     maxLength = Math.max(maxLength, current - startSequence);
    745                     startSequence = current - 1;
    746                 }
    747                 diff = currentDiff;
    748                 hasDiff = true;
    749             }
    750             previousChar = currentChar;
    751         }
    752         maxLength = Math.max(maxLength, string.length() - startSequence);
    753         return maxLength;
    754     }
    755 
    756     /** Update the encryption password if it is enabled **/
    757     private void updateEncryptionPassword(final int type, final String password) {
    758         if (!isDeviceEncryptionEnabled()) {
    759             return;
    760         }
    761         final IBinder service = ServiceManager.getService("mount");
    762         if (service == null) {
    763             Log.e(TAG, "Could not find the mount service to update the encryption password");
    764             return;
    765         }
    766 
    767         new AsyncTask<Void, Void, Void>() {
    768             @Override
    769             protected Void doInBackground(Void... dummy) {
    770                 IMountService mountService = IMountService.Stub.asInterface(service);
    771                 try {
    772                     mountService.changeEncryptionPassword(type, password);
    773                 } catch (RemoteException e) {
    774                     Log.e(TAG, "Error changing encryption password", e);
    775                 }
    776                 return null;
    777             }
    778         }.execute();
    779     }
    780 
    781     /**
    782      * Save a lock password.  Does not ensure that the password is as good
    783      * as the requested mode, but will adjust the mode to be as good as the
    784      * pattern.
    785      * @param password The password to save
    786      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    787      */
    788     public void saveLockPassword(String password, int quality) {
    789         this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
    790     }
    791 
    792     /**
    793      * Save a lock password.  Does not ensure that the password is as good
    794      * as the requested mode, but will adjust the mode to be as good as the
    795      * pattern.
    796      * @param password The password to save
    797      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    798      * @param isFallback Specifies if this is a fallback to biometric weak
    799      */
    800     public void saveLockPassword(String password, int quality, boolean isFallback) {
    801         saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
    802     }
    803 
    804     /**
    805      * Save a lock password.  Does not ensure that the password is as good
    806      * as the requested mode, but will adjust the mode to be as good as the
    807      * pattern.
    808      * @param password The password to save
    809      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    810      * @param isFallback Specifies if this is a fallback to biometric weak
    811      * @param userHandle The userId of the user to change the password for
    812      */
    813     public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
    814         try {
    815             DevicePolicyManager dpm = getDevicePolicyManager();
    816             if (!TextUtils.isEmpty(password)) {
    817                 getLockSettings().setLockPassword(password, userHandle);
    818                 int computedQuality = computePasswordQuality(password);
    819 
    820                 // Update the device encryption password.
    821                 if (userHandle == UserHandle.USER_OWNER
    822                         && LockPatternUtils.isDeviceEncryptionEnabled()) {
    823                     if (!isCredentialRequiredToDecrypt(true)) {
    824                         clearEncryptionPassword();
    825                     } else {
    826                         boolean numeric = computedQuality
    827                                 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
    828                         boolean numericComplex = computedQuality
    829                                 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
    830                         int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
    831                                 : StorageManager.CRYPT_TYPE_PASSWORD;
    832                         updateEncryptionPassword(type, password);
    833                     }
    834                 }
    835 
    836                 if (!isFallback) {
    837                     deleteGallery(userHandle);
    838                     setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
    839                     if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    840                         int letters = 0;
    841                         int uppercase = 0;
    842                         int lowercase = 0;
    843                         int numbers = 0;
    844                         int symbols = 0;
    845                         int nonletter = 0;
    846                         for (int i = 0; i < password.length(); i++) {
    847                             char c = password.charAt(i);
    848                             if (c >= 'A' && c <= 'Z') {
    849                                 letters++;
    850                                 uppercase++;
    851                             } else if (c >= 'a' && c <= 'z') {
    852                                 letters++;
    853                                 lowercase++;
    854                             } else if (c >= '0' && c <= '9') {
    855                                 numbers++;
    856                                 nonletter++;
    857                             } else {
    858                                 symbols++;
    859                                 nonletter++;
    860                             }
    861                         }
    862                         dpm.setActivePasswordState(Math.max(quality, computedQuality),
    863                                 password.length(), letters, uppercase, lowercase,
    864                                 numbers, symbols, nonletter, userHandle);
    865                     } else {
    866                         // The password is not anything.
    867                         dpm.setActivePasswordState(
    868                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    869                                 0, 0, 0, 0, 0, 0, 0, userHandle);
    870                     }
    871                 } else {
    872                     // Case where it's a fallback for biometric weak
    873                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
    874                             userHandle);
    875                     setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
    876                             userHandle);
    877                     finishBiometricWeak(userHandle);
    878                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
    879                             0, 0, 0, 0, 0, 0, 0, userHandle);
    880                 }
    881                 // Add the password to the password history. We assume all
    882                 // password hashes have the same length for simplicity of implementation.
    883                 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
    884                 if (passwordHistory == null) {
    885                     passwordHistory = "";
    886                 }
    887                 int passwordHistoryLength = getRequestedPasswordHistoryLength();
    888                 if (passwordHistoryLength == 0) {
    889                     passwordHistory = "";
    890                 } else {
    891                     byte[] hash = passwordToHash(password, userHandle);
    892                     passwordHistory = new String(hash) + "," + passwordHistory;
    893                     // Cut it to contain passwordHistoryLength hashes
    894                     // and passwordHistoryLength -1 commas.
    895                     passwordHistory = passwordHistory.substring(0, Math.min(hash.length
    896                             * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
    897                             .length()));
    898                 }
    899                 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
    900             } else {
    901                 // Empty password
    902                 getLockSettings().setLockPassword(null, userHandle);
    903                 if (userHandle == UserHandle.USER_OWNER) {
    904                     // Set the encryption password to default.
    905                     updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
    906                 }
    907 
    908                 dpm.setActivePasswordState(
    909                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
    910                         userHandle);
    911             }
    912             onAfterChangingPassword(userHandle);
    913         } catch (RemoteException re) {
    914             // Cant do much
    915             Log.e(TAG, "Unable to save lock password " + re);
    916         }
    917     }
    918 
    919     /**
    920      * Gets whether the device is encrypted.
    921      *
    922      * @return Whether the device is encrypted.
    923      */
    924     public static boolean isDeviceEncrypted() {
    925         IMountService mountService = IMountService.Stub.asInterface(
    926                 ServiceManager.getService("mount"));
    927         try {
    928             return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
    929                     && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
    930         } catch (RemoteException re) {
    931             Log.e(TAG, "Error getting encryption state", re);
    932         }
    933         return true;
    934     }
    935 
    936     /**
    937      * Determine if the device supports encryption, even if it's set to default. This
    938      * differs from isDeviceEncrypted() in that it returns true even if the device is
    939      * encrypted with the default password.
    940      * @return true if device encryption is enabled
    941      */
    942     public static boolean isDeviceEncryptionEnabled() {
    943         final String status = SystemProperties.get("ro.crypto.state", "unsupported");
    944         return "encrypted".equalsIgnoreCase(status);
    945     }
    946 
    947     /**
    948      * Clears the encryption password.
    949      */
    950     public void clearEncryptionPassword() {
    951         updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
    952     }
    953 
    954     /**
    955      * Retrieves the quality mode we're in.
    956      * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    957      *
    958      * @return stored password quality
    959      */
    960     public int getKeyguardStoredPasswordQuality() {
    961         return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId());
    962     }
    963 
    964     /**
    965      * Retrieves the quality mode for {@param userHandle}.
    966      * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    967      *
    968      * @return stored password quality
    969      */
    970     public int getKeyguardStoredPasswordQuality(int userHandle) {
    971         int quality = (int) getLong(PASSWORD_TYPE_KEY,
    972                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    973         // If the user has chosen to use weak biometric sensor, then return the backup locking
    974         // method and treat biometric as a special case.
    975         if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
    976             quality = (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
    977                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    978         }
    979         return quality;
    980     }
    981 
    982     /**
    983      * @return true if the lockscreen method is set to biometric weak
    984      */
    985     public boolean usingBiometricWeak() {
    986         return usingBiometricWeak(getCurrentOrCallingUserId());
    987     }
    988 
    989     /**
    990      * @return true if the lockscreen method is set to biometric weak
    991      */
    992     public boolean usingBiometricWeak(int userId) {
    993         int quality = (int) getLong(
    994                 PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
    995         return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
    996     }
    997 
    998     /**
    999      * Deserialize a pattern.
   1000      * @param string The pattern serialized with {@link #patternToString}
   1001      * @return The pattern.
   1002      */
   1003     public static List<LockPatternView.Cell> stringToPattern(String string) {
   1004         List<LockPatternView.Cell> result = Lists.newArrayList();
   1005 
   1006         final byte[] bytes = string.getBytes();
   1007         for (int i = 0; i < bytes.length; i++) {
   1008             byte b = bytes[i];
   1009             result.add(LockPatternView.Cell.of(b / 3, b % 3));
   1010         }
   1011         return result;
   1012     }
   1013 
   1014     /**
   1015      * Serialize a pattern.
   1016      * @param pattern The pattern.
   1017      * @return The pattern in string form.
   1018      */
   1019     public static String patternToString(List<LockPatternView.Cell> pattern) {
   1020         if (pattern == null) {
   1021             return "";
   1022         }
   1023         final int patternSize = pattern.size();
   1024 
   1025         byte[] res = new byte[patternSize];
   1026         for (int i = 0; i < patternSize; i++) {
   1027             LockPatternView.Cell cell = pattern.get(i);
   1028             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
   1029         }
   1030         return new String(res);
   1031     }
   1032 
   1033     /*
   1034      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
   1035      * at least a second level of protection. First level is that the file
   1036      * is in a location only readable by the system process.
   1037      * @param pattern the gesture pattern.
   1038      * @return the hash of the pattern in a byte array.
   1039      */
   1040     public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
   1041         if (pattern == null) {
   1042             return null;
   1043         }
   1044 
   1045         final int patternSize = pattern.size();
   1046         byte[] res = new byte[patternSize];
   1047         for (int i = 0; i < patternSize; i++) {
   1048             LockPatternView.Cell cell = pattern.get(i);
   1049             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
   1050         }
   1051         try {
   1052             MessageDigest md = MessageDigest.getInstance("SHA-1");
   1053             byte[] hash = md.digest(res);
   1054             return hash;
   1055         } catch (NoSuchAlgorithmException nsa) {
   1056             return res;
   1057         }
   1058     }
   1059 
   1060     private String getSalt(int userId) {
   1061         long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
   1062         if (salt == 0) {
   1063             try {
   1064                 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
   1065                 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
   1066                 Log.v(TAG, "Initialized lock password salt for user: " + userId);
   1067             } catch (NoSuchAlgorithmException e) {
   1068                 // Throw an exception rather than storing a password we'll never be able to recover
   1069                 throw new IllegalStateException("Couldn't get SecureRandom number", e);
   1070             }
   1071         }
   1072         return Long.toHexString(salt);
   1073     }
   1074 
   1075     /*
   1076      * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
   1077      * Not the most secure, but it is at least a second level of protection. First level is that
   1078      * the file is in a location only readable by the system process.
   1079      * @param password the gesture pattern.
   1080      * @return the hash of the pattern in a byte array.
   1081      */
   1082     public byte[] passwordToHash(String password, int userId) {
   1083         if (password == null) {
   1084             return null;
   1085         }
   1086         String algo = null;
   1087         byte[] hashed = null;
   1088         try {
   1089             byte[] saltedPassword = (password + getSalt(userId)).getBytes();
   1090             byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
   1091             byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
   1092             hashed = (toHex(sha1) + toHex(md5)).getBytes();
   1093         } catch (NoSuchAlgorithmException e) {
   1094             Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
   1095         }
   1096         return hashed;
   1097     }
   1098 
   1099     private static String toHex(byte[] ary) {
   1100         final String hex = "0123456789ABCDEF";
   1101         String ret = "";
   1102         for (int i = 0; i < ary.length; i++) {
   1103             ret += hex.charAt((ary[i] >> 4) & 0xf);
   1104             ret += hex.charAt(ary[i] & 0xf);
   1105         }
   1106         return ret;
   1107     }
   1108 
   1109     /**
   1110      * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
   1111      */
   1112     public boolean isLockPasswordEnabled() {
   1113         long mode = getLong(PASSWORD_TYPE_KEY, 0);
   1114         long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
   1115         final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
   1116                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
   1117                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
   1118                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
   1119                 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
   1120         final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
   1121                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
   1122                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
   1123                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
   1124                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
   1125 
   1126         return savedPasswordExists() && (passwordEnabled ||
   1127                 (usingBiometricWeak() && backupEnabled));
   1128     }
   1129 
   1130     /**
   1131      * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
   1132      */
   1133     public boolean isLockPatternEnabled() {
   1134         return isLockPatternEnabled(getCurrentOrCallingUserId());
   1135     }
   1136 
   1137     /**
   1138      * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
   1139      */
   1140     public boolean isLockPatternEnabled(int userId) {
   1141         final boolean backupEnabled =
   1142                 getLong(PASSWORD_TYPE_ALTERNATE_KEY,
   1143                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId)
   1144                                 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
   1145 
   1146         return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false, userId)
   1147                 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
   1148                         userId) == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
   1149                         || (usingBiometricWeak(userId) && backupEnabled));
   1150     }
   1151 
   1152     /**
   1153      * @return Whether biometric weak lock is installed and that the front facing camera exists
   1154      */
   1155     public boolean isBiometricWeakInstalled() {
   1156         // Check that it's installed
   1157         PackageManager pm = mContext.getPackageManager();
   1158         try {
   1159             pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
   1160         } catch (PackageManager.NameNotFoundException e) {
   1161             return false;
   1162         }
   1163 
   1164         // Check that the camera is enabled
   1165         if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
   1166             return false;
   1167         }
   1168         if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
   1169             return false;
   1170         }
   1171 
   1172         // TODO: If we decide not to proceed with Face Unlock as a trustlet, this must be changed
   1173         // back to returning true.  If we become certain that Face Unlock will be a trustlet, this
   1174         // entire function and a lot of other code can be removed.
   1175         if (DEBUG) Log.d(TAG, "Forcing isBiometricWeakInstalled() to return false to disable it");
   1176         return false;
   1177     }
   1178 
   1179     /**
   1180      * Set whether biometric weak liveliness is enabled.
   1181      */
   1182     public void setBiometricWeakLivelinessEnabled(boolean enabled) {
   1183         long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
   1184         long newFlag;
   1185         if (enabled) {
   1186             newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
   1187         } else {
   1188             newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
   1189         }
   1190         setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
   1191     }
   1192 
   1193     /**
   1194      * @return Whether the biometric weak liveliness is enabled.
   1195      */
   1196     public boolean isBiometricWeakLivelinessEnabled() {
   1197         long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
   1198         return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
   1199     }
   1200 
   1201     /**
   1202      * Set whether the lock pattern is enabled.
   1203      */
   1204     public void setLockPatternEnabled(boolean enabled) {
   1205         setLockPatternEnabled(enabled, getCurrentOrCallingUserId());
   1206     }
   1207 
   1208     /**
   1209      * Set whether the lock pattern is enabled.
   1210      */
   1211     public void setLockPatternEnabled(boolean enabled, int userHandle) {
   1212         setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled, userHandle);
   1213     }
   1214 
   1215     /**
   1216      * @return Whether the visible pattern is enabled.
   1217      */
   1218     public boolean isVisiblePatternEnabled() {
   1219         return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
   1220     }
   1221 
   1222     /**
   1223      * Set whether the visible pattern is enabled.
   1224      */
   1225     public void setVisiblePatternEnabled(boolean enabled) {
   1226         setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
   1227 
   1228         // Update for crypto if owner
   1229         int userId = getCurrentOrCallingUserId();
   1230         if (userId != UserHandle.USER_OWNER) {
   1231             return;
   1232         }
   1233 
   1234         IBinder service = ServiceManager.getService("mount");
   1235         if (service == null) {
   1236             Log.e(TAG, "Could not find the mount service to update the user info");
   1237             return;
   1238         }
   1239 
   1240         IMountService mountService = IMountService.Stub.asInterface(service);
   1241         try {
   1242             mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
   1243         } catch (RemoteException e) {
   1244             Log.e(TAG, "Error changing pattern visible state", e);
   1245         }
   1246     }
   1247 
   1248     /**
   1249      * @return Whether tactile feedback for the pattern is enabled.
   1250      */
   1251     public boolean isTactileFeedbackEnabled() {
   1252         return Settings.System.getIntForUser(mContentResolver,
   1253                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
   1254     }
   1255 
   1256     /**
   1257      * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
   1258      * pattern until the deadline has passed.
   1259      * @return the chosen deadline.
   1260      */
   1261     public long setLockoutAttemptDeadline() {
   1262         final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
   1263         setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
   1264         return deadline;
   1265     }
   1266 
   1267     /**
   1268      * @return The elapsed time in millis in the future when the user is allowed to
   1269      *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
   1270      *   enter a pattern.
   1271      */
   1272     public long getLockoutAttemptDeadline() {
   1273         final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
   1274         final long now = SystemClock.elapsedRealtime();
   1275         if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
   1276             return 0L;
   1277         }
   1278         return deadline;
   1279     }
   1280 
   1281     /**
   1282      * @return Whether the user is permanently locked out until they verify their
   1283      *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
   1284      *   attempts.
   1285      */
   1286     public boolean isPermanentlyLocked() {
   1287         return getBoolean(LOCKOUT_PERMANENT_KEY, false);
   1288     }
   1289 
   1290     /**
   1291      * Set the state of whether the device is permanently locked, meaning the user
   1292      * must authenticate via other means.
   1293      *
   1294      * @param locked Whether the user is permanently locked out until they verify their
   1295      *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
   1296      *   attempts.
   1297      */
   1298     public void setPermanentlyLocked(boolean locked) {
   1299         setBoolean(LOCKOUT_PERMANENT_KEY, locked);
   1300     }
   1301 
   1302     public boolean isEmergencyCallCapable() {
   1303         return mContext.getResources().getBoolean(
   1304                 com.android.internal.R.bool.config_voice_capable);
   1305     }
   1306 
   1307     public boolean isPukUnlockScreenEnable() {
   1308         return mContext.getResources().getBoolean(
   1309                 com.android.internal.R.bool.config_enable_puk_unlock_screen);
   1310     }
   1311 
   1312     public boolean isEmergencyCallEnabledWhileSimLocked() {
   1313         return mContext.getResources().getBoolean(
   1314                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
   1315     }
   1316 
   1317     /**
   1318      * @return A formatted string of the next alarm (for showing on the lock screen),
   1319      *   or null if there is no next alarm.
   1320      */
   1321     public AlarmManager.AlarmClockInfo getNextAlarm() {
   1322         AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
   1323         return alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
   1324     }
   1325 
   1326     private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
   1327         try {
   1328             return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
   1329         } catch (RemoteException re) {
   1330             return defaultValue;
   1331         }
   1332     }
   1333 
   1334     private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
   1335         return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
   1336     }
   1337 
   1338     private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
   1339         try {
   1340             getLockSettings().setBoolean(secureSettingKey, enabled, userId);
   1341         } catch (RemoteException re) {
   1342             // What can we do?
   1343             Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
   1344         }
   1345     }
   1346 
   1347     private void setBoolean(String secureSettingKey, boolean enabled) {
   1348         setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
   1349     }
   1350 
   1351     public int[] getAppWidgets() {
   1352         return getAppWidgets(UserHandle.USER_CURRENT);
   1353     }
   1354 
   1355     private int[] getAppWidgets(int userId) {
   1356         String appWidgetIdString = Settings.Secure.getStringForUser(
   1357                 mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
   1358         String delims = ",";
   1359         if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
   1360             String[] appWidgetStringIds = appWidgetIdString.split(delims);
   1361             int[] appWidgetIds = new int[appWidgetStringIds.length];
   1362             for (int i = 0; i < appWidgetStringIds.length; i++) {
   1363                 String appWidget = appWidgetStringIds[i];
   1364                 try {
   1365                     appWidgetIds[i] = Integer.decode(appWidget);
   1366                 } catch (NumberFormatException e) {
   1367                     Log.d(TAG, "Error when parsing widget id " + appWidget);
   1368                     return null;
   1369                 }
   1370             }
   1371             return appWidgetIds;
   1372         }
   1373         return new int[0];
   1374     }
   1375 
   1376     private static String combineStrings(int[] list, String separator) {
   1377         int listLength = list.length;
   1378 
   1379         switch (listLength) {
   1380             case 0: {
   1381                 return "";
   1382             }
   1383             case 1: {
   1384                 return Integer.toString(list[0]);
   1385             }
   1386         }
   1387 
   1388         int strLength = 0;
   1389         int separatorLength = separator.length();
   1390 
   1391         String[] stringList = new String[list.length];
   1392         for (int i = 0; i < listLength; i++) {
   1393             stringList[i] = Integer.toString(list[i]);
   1394             strLength += stringList[i].length();
   1395             if (i < listLength - 1) {
   1396                 strLength += separatorLength;
   1397             }
   1398         }
   1399 
   1400         StringBuilder sb = new StringBuilder(strLength);
   1401 
   1402         for (int i = 0; i < listLength; i++) {
   1403             sb.append(list[i]);
   1404             if (i < listLength - 1) {
   1405                 sb.append(separator);
   1406             }
   1407         }
   1408 
   1409         return sb.toString();
   1410     }
   1411 
   1412     // appwidget used when appwidgets are disabled (we make an exception for
   1413     // default clock widget)
   1414     public void writeFallbackAppWidgetId(int appWidgetId) {
   1415         Settings.Secure.putIntForUser(mContentResolver,
   1416                 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
   1417                 appWidgetId,
   1418                 UserHandle.USER_CURRENT);
   1419     }
   1420 
   1421     // appwidget used when appwidgets are disabled (we make an exception for
   1422     // default clock widget)
   1423     public int getFallbackAppWidgetId() {
   1424         return Settings.Secure.getIntForUser(
   1425                 mContentResolver,
   1426                 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
   1427                 AppWidgetManager.INVALID_APPWIDGET_ID,
   1428                 UserHandle.USER_CURRENT);
   1429     }
   1430 
   1431     private void writeAppWidgets(int[] appWidgetIds) {
   1432         Settings.Secure.putStringForUser(mContentResolver,
   1433                         Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
   1434                         combineStrings(appWidgetIds, ","),
   1435                         UserHandle.USER_CURRENT);
   1436     }
   1437 
   1438     // TODO: log an error if this returns false
   1439     public boolean addAppWidget(int widgetId, int index) {
   1440         int[] widgets = getAppWidgets();
   1441         if (widgets == null) {
   1442             return false;
   1443         }
   1444         if (index < 0 || index > widgets.length) {
   1445             return false;
   1446         }
   1447         int[] newWidgets = new int[widgets.length + 1];
   1448         for (int i = 0, j = 0; i < newWidgets.length; i++) {
   1449             if (index == i) {
   1450                 newWidgets[i] = widgetId;
   1451                 i++;
   1452             }
   1453             if (i < newWidgets.length) {
   1454                 newWidgets[i] = widgets[j];
   1455                 j++;
   1456             }
   1457         }
   1458         writeAppWidgets(newWidgets);
   1459         return true;
   1460     }
   1461 
   1462     public boolean removeAppWidget(int widgetId) {
   1463         int[] widgets = getAppWidgets();
   1464 
   1465         if (widgets.length == 0) {
   1466             return false;
   1467         }
   1468 
   1469         int[] newWidgets = new int[widgets.length - 1];
   1470         for (int i = 0, j = 0; i < widgets.length; i++) {
   1471             if (widgets[i] == widgetId) {
   1472                 // continue...
   1473             } else if (j >= newWidgets.length) {
   1474                 // we couldn't find the widget
   1475                 return false;
   1476             } else {
   1477                 newWidgets[j] = widgets[i];
   1478                 j++;
   1479             }
   1480         }
   1481         writeAppWidgets(newWidgets);
   1482         return true;
   1483     }
   1484 
   1485     private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
   1486         try {
   1487             return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
   1488         } catch (RemoteException re) {
   1489             return defaultValue;
   1490         }
   1491     }
   1492 
   1493     private long getLong(String secureSettingKey, long defaultValue) {
   1494         try {
   1495             return getLockSettings().getLong(secureSettingKey, defaultValue,
   1496                     getCurrentOrCallingUserId());
   1497         } catch (RemoteException re) {
   1498             return defaultValue;
   1499         }
   1500     }
   1501 
   1502     private void setLong(String secureSettingKey, long value) {
   1503         setLong(secureSettingKey, value, getCurrentOrCallingUserId());
   1504     }
   1505 
   1506     private void setLong(String secureSettingKey, long value, int userHandle) {
   1507         try {
   1508             getLockSettings().setLong(secureSettingKey, value, userHandle);
   1509         } catch (RemoteException re) {
   1510             // What can we do?
   1511             Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
   1512         }
   1513     }
   1514 
   1515     private String getString(String secureSettingKey) {
   1516         return getString(secureSettingKey, getCurrentOrCallingUserId());
   1517     }
   1518 
   1519     private String getString(String secureSettingKey, int userHandle) {
   1520         try {
   1521             return getLockSettings().getString(secureSettingKey, null, userHandle);
   1522         } catch (RemoteException re) {
   1523             return null;
   1524         }
   1525     }
   1526 
   1527     private void setString(String secureSettingKey, String value, int userHandle) {
   1528         try {
   1529             getLockSettings().setString(secureSettingKey, value, userHandle);
   1530         } catch (RemoteException re) {
   1531             // What can we do?
   1532             Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
   1533         }
   1534     }
   1535 
   1536     public boolean isSecure() {
   1537         return isSecure(getCurrentOrCallingUserId());
   1538     }
   1539 
   1540     public boolean isSecure(int userId) {
   1541         long mode = getKeyguardStoredPasswordQuality(userId);
   1542         final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
   1543         final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
   1544                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
   1545                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
   1546                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
   1547                 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
   1548         final boolean secure =
   1549                 isPattern && isLockPatternEnabled(userId) && savedPatternExists(userId)
   1550                 || isPassword && savedPasswordExists(userId);
   1551         return secure;
   1552     }
   1553 
   1554     /**
   1555      * Sets the emergency button visibility based on isEmergencyCallCapable().
   1556      *
   1557      * If the emergency button is visible, sets the text on the emergency button
   1558      * to indicate what action will be taken.
   1559      *
   1560      * If there's currently a call in progress, the button will take them to the call
   1561      * @param button The button to update
   1562      * @param shown Indicates whether the given screen wants the emergency button to show at all
   1563      * @param showIcon Indicates whether to show a phone icon for the button.
   1564      */
   1565     public void updateEmergencyCallButtonState(Button button, boolean shown, boolean showIcon) {
   1566         if (isEmergencyCallCapable() && shown) {
   1567             button.setVisibility(View.VISIBLE);
   1568         } else {
   1569             button.setVisibility(View.GONE);
   1570             return;
   1571         }
   1572 
   1573         int textId;
   1574         if (isInCall()) {
   1575             // show "return to call" text and show phone icon
   1576             textId = R.string.lockscreen_return_to_call;
   1577             int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
   1578             button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
   1579         } else {
   1580             textId = R.string.lockscreen_emergency_call;
   1581             int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
   1582             button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
   1583         }
   1584         button.setText(textId);
   1585     }
   1586 
   1587     /**
   1588      * Resumes a call in progress. Typically launched from the EmergencyCall button
   1589      * on various lockscreens.
   1590      */
   1591     public void resumeCall() {
   1592         getTelecommManager().showInCallScreen(false);
   1593     }
   1594 
   1595     /**
   1596      * @return {@code true} if there is a call currently in progress, {@code false} otherwise.
   1597      */
   1598     public boolean isInCall() {
   1599         return getTelecommManager().isInCall();
   1600     }
   1601 
   1602     private TelecomManager getTelecommManager() {
   1603         return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
   1604     }
   1605 
   1606     private void finishBiometricWeak(int userId) {
   1607         setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true, userId);
   1608 
   1609         // Launch intent to show final screen, this also
   1610         // moves the temporary gallery to the actual gallery
   1611         Intent intent = new Intent();
   1612         intent.setClassName("com.android.facelock",
   1613                 "com.android.facelock.SetupEndScreen");
   1614         mContext.startActivityAsUser(intent, new UserHandle(userId));
   1615     }
   1616 
   1617     public void setPowerButtonInstantlyLocks(boolean enabled) {
   1618         setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
   1619     }
   1620 
   1621     public boolean getPowerButtonInstantlyLocks() {
   1622         return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
   1623     }
   1624 
   1625     public static boolean isSafeModeEnabled() {
   1626         try {
   1627             return IWindowManager.Stub.asInterface(
   1628                     ServiceManager.getService("window")).isSafeModeEnabled();
   1629         } catch (RemoteException e) {
   1630             // Shouldn't happen!
   1631         }
   1632         return false;
   1633     }
   1634 
   1635     /**
   1636      * Determine whether the user has selected any non-system widgets in keyguard
   1637      *
   1638      * @return true if widgets have been selected
   1639      */
   1640     public boolean hasWidgetsEnabledInKeyguard(int userid) {
   1641         int widgets[] = getAppWidgets(userid);
   1642         for (int i = 0; i < widgets.length; i++) {
   1643             if (widgets[i] > 0) {
   1644                 return true;
   1645             }
   1646         }
   1647         return false;
   1648     }
   1649 
   1650     public boolean getWidgetsEnabled() {
   1651         return getWidgetsEnabled(getCurrentOrCallingUserId());
   1652     }
   1653 
   1654     public boolean getWidgetsEnabled(int userId) {
   1655         return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
   1656     }
   1657 
   1658     public void setWidgetsEnabled(boolean enabled) {
   1659         setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
   1660     }
   1661 
   1662     public void setWidgetsEnabled(boolean enabled, int userId) {
   1663         setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
   1664     }
   1665 
   1666     public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
   1667         setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
   1668     }
   1669 
   1670     public List<ComponentName> getEnabledTrustAgents() {
   1671         return getEnabledTrustAgents(getCurrentOrCallingUserId());
   1672     }
   1673 
   1674     public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
   1675         StringBuilder sb = new StringBuilder();
   1676         for (ComponentName cn : activeTrustAgents) {
   1677             if (sb.length() > 0) {
   1678                 sb.append(',');
   1679             }
   1680             sb.append(cn.flattenToShortString());
   1681         }
   1682         setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
   1683         getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
   1684     }
   1685 
   1686     public List<ComponentName> getEnabledTrustAgents(int userId) {
   1687         String serialized = getString(ENABLED_TRUST_AGENTS, userId);
   1688         if (TextUtils.isEmpty(serialized)) {
   1689             return null;
   1690         }
   1691         String[] split = serialized.split(",");
   1692         ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
   1693         for (String s : split) {
   1694             if (!TextUtils.isEmpty(s)) {
   1695                 activeTrustAgents.add(ComponentName.unflattenFromString(s));
   1696             }
   1697         }
   1698         return activeTrustAgents;
   1699     }
   1700 
   1701     /**
   1702      * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
   1703      */
   1704     public void requireCredentialEntry(int userId) {
   1705         getTrustManager().reportRequireCredentialEntry(userId);
   1706     }
   1707 
   1708     private void onAfterChangingPassword(int userHandle) {
   1709         getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
   1710     }
   1711 
   1712     public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
   1713         final int value = Settings.Global.getInt(mContentResolver,
   1714                 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
   1715         return value == -1 ? defaultValue : (value != 0);
   1716     }
   1717 
   1718     public void setCredentialRequiredToDecrypt(boolean required) {
   1719         if (getCurrentUser() != UserHandle.USER_OWNER) {
   1720             Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
   1721             return;
   1722         }
   1723         Settings.Global.putInt(mContext.getContentResolver(),
   1724                 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
   1725     }
   1726 }
   1727