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