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.admin.DevicePolicyManager;
     22 import android.appwidget.AppWidgetManager;
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.pm.PackageManager;
     27 import android.os.Binder;
     28 import android.os.IBinder;
     29 import android.os.RemoteException;
     30 import android.os.ServiceManager;
     31 import android.os.SystemClock;
     32 import android.os.UserHandle;
     33 import android.os.storage.IMountService;
     34 import android.provider.Settings;
     35 import android.telephony.TelephonyManager;
     36 import android.text.TextUtils;
     37 import android.util.Log;
     38 import android.view.IWindowManager;
     39 import android.view.View;
     40 import android.widget.Button;
     41 
     42 import com.android.internal.R;
     43 import com.android.internal.telephony.ITelephony;
     44 import com.google.android.collect.Lists;
     45 
     46 import java.security.MessageDigest;
     47 import java.security.NoSuchAlgorithmException;
     48 import java.security.SecureRandom;
     49 import java.util.List;
     50 
     51 /**
     52  * Utilities for the lock pattern and its settings.
     53  */
     54 public class LockPatternUtils {
     55 
     56     private static final String TAG = "LockPatternUtils";
     57 
     58     /**
     59      * The maximum number of incorrect attempts before the user is prevented
     60      * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
     61      */
     62     public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
     63 
     64     /**
     65      * The number of incorrect attempts before which we fall back on an alternative
     66      * method of verifying the user, and resetting their lock pattern.
     67      */
     68     public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
     69 
     70     /**
     71      * How long the user is prevented from trying again after entering the
     72      * wrong pattern too many times.
     73      */
     74     public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
     75 
     76     /**
     77      * The interval of the countdown for showing progress of the lockout.
     78      */
     79     public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
     80 
     81 
     82     /**
     83      * This dictates when we start telling the user that continued failed attempts will wipe
     84      * their device.
     85      */
     86     public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
     87 
     88     /**
     89      * The minimum number of dots in a valid pattern.
     90      */
     91     public static final int MIN_LOCK_PATTERN_SIZE = 4;
     92 
     93     /**
     94      * The minimum number of dots the user must include in a wrong pattern
     95      * attempt for it to be counted against the counts that affect
     96      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
     97      */
     98     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
     99 
    100     /**
    101      * Tells the keyguard to show the user switcher when the keyguard is created.
    102      */
    103     public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
    104 
    105     /**
    106      * Tells the keyguard to show the security challenge when the keyguard is created.
    107      */
    108     public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
    109 
    110     /**
    111      * Tells the keyguard to show the widget with the specified id when the keyguard is created.
    112      */
    113     public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
    114 
    115     /**
    116      * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
    117      * be used
    118      */
    119     public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
    120 
    121     /**
    122      * Pseudo-appwidget id we use to represent the default clock status widget
    123      */
    124     public static final int ID_DEFAULT_STATUS_WIDGET = -2;
    125 
    126     public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
    127     public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
    128     public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
    129     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
    130     public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
    131     public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
    132     public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
    133     public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
    134     public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
    135             = "lockscreen.biometric_weak_fallback";
    136     public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
    137             = "lockscreen.biometricweakeverchosen";
    138     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
    139             = "lockscreen.power_button_instantly_locks";
    140     public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
    141 
    142     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
    143 
    144     private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
    145     private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
    146             Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    147 
    148     private final Context mContext;
    149     private final ContentResolver mContentResolver;
    150     private DevicePolicyManager mDevicePolicyManager;
    151     private ILockSettings mLockSettingsService;
    152 
    153     private final boolean mMultiUserMode;
    154 
    155     // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
    156     private static volatile int sCurrentUserId = UserHandle.USER_NULL;
    157 
    158     public DevicePolicyManager getDevicePolicyManager() {
    159         if (mDevicePolicyManager == null) {
    160             mDevicePolicyManager =
    161                 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    162             if (mDevicePolicyManager == null) {
    163                 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
    164                         new IllegalStateException("Stack trace:"));
    165             }
    166         }
    167         return mDevicePolicyManager;
    168     }
    169 
    170     /**
    171      * @param contentResolver Used to look up and save settings.
    172      */
    173     public LockPatternUtils(Context context) {
    174         mContext = context;
    175         mContentResolver = context.getContentResolver();
    176 
    177         // If this is being called by the system or by an application like keyguard that
    178         // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
    179         // mode where calls are for the current user rather than the user of the calling process.
    180         mMultiUserMode = context.checkCallingOrSelfPermission(
    181             Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
    182     }
    183 
    184     private ILockSettings getLockSettings() {
    185         if (mLockSettingsService == null) {
    186             mLockSettingsService = ILockSettings.Stub.asInterface(
    187                 (IBinder) ServiceManager.getService("lock_settings"));
    188         }
    189         return mLockSettingsService;
    190     }
    191 
    192     public int getRequestedMinimumPasswordLength() {
    193         return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
    194     }
    195 
    196     /**
    197      * Gets the device policy password mode. If the mode is non-specific, returns
    198      * MODE_PATTERN which allows the user to choose anything.
    199      */
    200     public int getRequestedPasswordQuality() {
    201         return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
    202     }
    203 
    204     public int getRequestedPasswordHistoryLength() {
    205         return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
    206     }
    207 
    208     public int getRequestedPasswordMinimumLetters() {
    209         return getDevicePolicyManager().getPasswordMinimumLetters(null,
    210                 getCurrentOrCallingUserId());
    211     }
    212 
    213     public int getRequestedPasswordMinimumUpperCase() {
    214         return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
    215                 getCurrentOrCallingUserId());
    216     }
    217 
    218     public int getRequestedPasswordMinimumLowerCase() {
    219         return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
    220                 getCurrentOrCallingUserId());
    221     }
    222 
    223     public int getRequestedPasswordMinimumNumeric() {
    224         return getDevicePolicyManager().getPasswordMinimumNumeric(null,
    225                 getCurrentOrCallingUserId());
    226     }
    227 
    228     public int getRequestedPasswordMinimumSymbols() {
    229         return getDevicePolicyManager().getPasswordMinimumSymbols(null,
    230                 getCurrentOrCallingUserId());
    231     }
    232 
    233     public int getRequestedPasswordMinimumNonLetter() {
    234         return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
    235                 getCurrentOrCallingUserId());
    236     }
    237 
    238     /**
    239      * Returns the actual password mode, as set by keyguard after updating the password.
    240      *
    241      * @return
    242      */
    243     public void reportFailedPasswordAttempt() {
    244         getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
    245     }
    246 
    247     public void reportSuccessfulPasswordAttempt() {
    248         getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
    249     }
    250 
    251     public void setCurrentUser(int userId) {
    252         sCurrentUserId = userId;
    253     }
    254 
    255     public int getCurrentUser() {
    256         if (sCurrentUserId != UserHandle.USER_NULL) {
    257             // Someone is regularly updating using setCurrentUser() use that value.
    258             return sCurrentUserId;
    259         }
    260         try {
    261             return ActivityManagerNative.getDefault().getCurrentUser().id;
    262         } catch (RemoteException re) {
    263             return UserHandle.USER_OWNER;
    264         }
    265     }
    266 
    267     public void removeUser(int userId) {
    268         try {
    269             getLockSettings().removeUser(userId);
    270         } catch (RemoteException re) {
    271             Log.e(TAG, "Couldn't remove lock settings for user " + userId);
    272         }
    273     }
    274 
    275     private int getCurrentOrCallingUserId() {
    276         if (mMultiUserMode) {
    277             // TODO: This is a little inefficient. See if all users of this are able to
    278             // handle USER_CURRENT and pass that instead.
    279             return getCurrentUser();
    280         } else {
    281             return UserHandle.getCallingUserId();
    282         }
    283     }
    284 
    285     /**
    286      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
    287      * always returns true.
    288      * @param pattern The pattern to check.
    289      * @return Whether the pattern matches the stored one.
    290      */
    291     public boolean checkPattern(List<LockPatternView.Cell> pattern) {
    292         final int userId = getCurrentOrCallingUserId();
    293         try {
    294             return getLockSettings().checkPattern(patternToString(pattern), userId);
    295         } catch (RemoteException re) {
    296             return true;
    297         }
    298     }
    299 
    300     /**
    301      * Check to see if a password matches the saved password.  If no password exists,
    302      * always returns true.
    303      * @param password The password to check.
    304      * @return Whether the password matches the stored one.
    305      */
    306     public boolean checkPassword(String password) {
    307         final int userId = getCurrentOrCallingUserId();
    308         try {
    309             return getLockSettings().checkPassword(password, userId);
    310         } catch (RemoteException re) {
    311             return true;
    312         }
    313     }
    314 
    315     /**
    316      * Check to see if a password matches any of the passwords stored in the
    317      * password history.
    318      *
    319      * @param password The password to check.
    320      * @return Whether the password matches any in the history.
    321      */
    322     public boolean checkPasswordHistory(String password) {
    323         String passwordHashString = new String(passwordToHash(password));
    324         String passwordHistory = getString(PASSWORD_HISTORY_KEY);
    325         if (passwordHistory == null) {
    326             return false;
    327         }
    328         // Password History may be too long...
    329         int passwordHashLength = passwordHashString.length();
    330         int passwordHistoryLength = getRequestedPasswordHistoryLength();
    331         if(passwordHistoryLength == 0) {
    332             return false;
    333         }
    334         int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
    335                 + passwordHistoryLength - 1;
    336         if (passwordHistory.length() > neededPasswordHistoryLength) {
    337             passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
    338         }
    339         return passwordHistory.contains(passwordHashString);
    340     }
    341 
    342     /**
    343      * Check to see if the user has stored a lock pattern.
    344      * @return Whether a saved pattern exists.
    345      */
    346     public boolean savedPatternExists() {
    347         try {
    348             return getLockSettings().havePattern(getCurrentOrCallingUserId());
    349         } catch (RemoteException re) {
    350             return false;
    351         }
    352     }
    353 
    354     /**
    355      * Check to see if the user has stored a lock pattern.
    356      * @return Whether a saved pattern exists.
    357      */
    358     public boolean savedPasswordExists() {
    359         try {
    360             return getLockSettings().havePassword(getCurrentOrCallingUserId());
    361         } catch (RemoteException re) {
    362             return false;
    363         }
    364     }
    365 
    366     /**
    367      * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
    368      * currently cleared.
    369      *
    370      * @return True if the user has ever chosen a pattern.
    371      */
    372     public boolean isPatternEverChosen() {
    373         return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
    374     }
    375 
    376     /**
    377      * Return true if the user has ever chosen biometric weak.  This is true even if biometric
    378      * weak is not current set.
    379      *
    380      * @return True if the user has ever chosen biometric weak.
    381      */
    382     public boolean isBiometricWeakEverChosen() {
    383         return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
    384     }
    385 
    386     /**
    387      * Used by device policy manager to validate the current password
    388      * information it has.
    389      */
    390     public int getActivePasswordQuality() {
    391         int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    392         // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
    393         // return biometric_weak if that is being used instead of the backup
    394         int quality =
    395                 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    396         switch (quality) {
    397             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
    398                 if (isLockPatternEnabled()) {
    399                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
    400                 }
    401                 break;
    402             case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
    403                 if (isBiometricWeakInstalled()) {
    404                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
    405                 }
    406                 break;
    407             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
    408                 if (isLockPasswordEnabled()) {
    409                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
    410                 }
    411                 break;
    412             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
    413                 if (isLockPasswordEnabled()) {
    414                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
    415                 }
    416                 break;
    417             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
    418                 if (isLockPasswordEnabled()) {
    419                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
    420                 }
    421                 break;
    422             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
    423                 if (isLockPasswordEnabled()) {
    424                     activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
    425                 }
    426                 break;
    427         }
    428 
    429         return activePasswordQuality;
    430     }
    431 
    432     /**
    433      * Clear any lock pattern or password.
    434      */
    435     public void clearLock(boolean isFallback) {
    436         if(!isFallback) deleteGallery();
    437         saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    438         setLockPatternEnabled(false);
    439         saveLockPattern(null);
    440         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
    441         setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
    442     }
    443 
    444     /**
    445      * Disable showing lock screen at all when the DevicePolicyManager allows it.
    446      * This is only meaningful if pattern, pin or password are not set.
    447      *
    448      * @param disable Disables lock screen when true
    449      */
    450     public void setLockScreenDisabled(boolean disable) {
    451         setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
    452     }
    453 
    454     /**
    455      * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
    456      * show LockScreen or go straight to the home screen.
    457      *
    458      * @return true if lock screen is can be disabled
    459      */
    460     public boolean isLockScreenDisabled() {
    461         return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
    462     }
    463 
    464     /**
    465      * Calls back SetupFaceLock to delete the temporary gallery file
    466      */
    467     public void deleteTempGallery() {
    468         Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
    469         intent.putExtra("deleteTempGallery", true);
    470         mContext.sendBroadcast(intent);
    471     }
    472 
    473     /**
    474      * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
    475     */
    476     void deleteGallery() {
    477         if(usingBiometricWeak()) {
    478             Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
    479             intent.putExtra("deleteGallery", true);
    480             mContext.sendBroadcast(intent);
    481         }
    482     }
    483 
    484     /**
    485      * Save a lock pattern.
    486      * @param pattern The new pattern to save.
    487      */
    488     public void saveLockPattern(List<LockPatternView.Cell> pattern) {
    489         this.saveLockPattern(pattern, false);
    490     }
    491 
    492     /**
    493      * Save a lock pattern.
    494      * @param pattern The new pattern to save.
    495      * @param isFallback Specifies if this is a fallback to biometric weak
    496      */
    497     public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
    498         try {
    499             getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
    500             DevicePolicyManager dpm = getDevicePolicyManager();
    501             if (pattern != null) {
    502                 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
    503                 if (!isFallback) {
    504                     deleteGallery();
    505                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    506                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
    507                             pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
    508                 } else {
    509                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
    510                     setLong(PASSWORD_TYPE_ALTERNATE_KEY,
    511                             DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    512                     finishBiometricWeak();
    513                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
    514                             0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
    515                 }
    516             } else {
    517                 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
    518                         0, 0, 0, 0, 0, getCurrentOrCallingUserId());
    519             }
    520         } catch (RemoteException re) {
    521             Log.e(TAG, "Couldn't save lock pattern " + re);
    522         }
    523     }
    524 
    525     public void setOwnerInfo(String info, int userId) {
    526         setString(LOCK_SCREEN_OWNER_INFO, info, userId);
    527     }
    528 
    529     public void setOwnerInfoEnabled(boolean enabled) {
    530         setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
    531     }
    532 
    533     public String getOwnerInfo(int userId) {
    534         return getString(LOCK_SCREEN_OWNER_INFO);
    535     }
    536 
    537     public boolean isOwnerInfoEnabled() {
    538         return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
    539     }
    540 
    541     /**
    542      * Compute the password quality from the given password string.
    543      */
    544     static public int computePasswordQuality(String password) {
    545         boolean hasDigit = false;
    546         boolean hasNonDigit = false;
    547         final int len = password.length();
    548         for (int i = 0; i < len; i++) {
    549             if (Character.isDigit(password.charAt(i))) {
    550                 hasDigit = true;
    551             } else {
    552                 hasNonDigit = true;
    553             }
    554         }
    555 
    556         if (hasNonDigit && hasDigit) {
    557             return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
    558         }
    559         if (hasNonDigit) {
    560             return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
    561         }
    562         if (hasDigit) {
    563             return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
    564         }
    565         return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    566     }
    567 
    568     /** Update the encryption password if it is enabled **/
    569     private void updateEncryptionPassword(String password) {
    570         DevicePolicyManager dpm = getDevicePolicyManager();
    571         if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
    572                 != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
    573             return;
    574         }
    575 
    576         IBinder service = ServiceManager.getService("mount");
    577         if (service == null) {
    578             Log.e(TAG, "Could not find the mount service to update the encryption password");
    579             return;
    580         }
    581 
    582         IMountService mountService = IMountService.Stub.asInterface(service);
    583         try {
    584             mountService.changeEncryptionPassword(password);
    585         } catch (RemoteException e) {
    586             Log.e(TAG, "Error changing encryption password", e);
    587         }
    588     }
    589 
    590     /**
    591      * Save a lock password.  Does not ensure that the password is as good
    592      * as the requested mode, but will adjust the mode to be as good as the
    593      * pattern.
    594      * @param password The password to save
    595      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    596      */
    597     public void saveLockPassword(String password, int quality) {
    598         this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
    599     }
    600 
    601     /**
    602      * Save a lock password.  Does not ensure that the password is as good
    603      * as the requested mode, but will adjust the mode to be as good as the
    604      * pattern.
    605      * @param password The password to save
    606      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    607      * @param isFallback Specifies if this is a fallback to biometric weak
    608      */
    609     public void saveLockPassword(String password, int quality, boolean isFallback) {
    610         saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
    611     }
    612 
    613     /**
    614      * Save a lock password.  Does not ensure that the password is as good
    615      * as the requested mode, but will adjust the mode to be as good as the
    616      * pattern.
    617      * @param password The password to save
    618      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    619      * @param isFallback Specifies if this is a fallback to biometric weak
    620      * @param userHandle The userId of the user to change the password for
    621      */
    622     public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
    623         try {
    624             getLockSettings().setLockPassword(password, userHandle);
    625             DevicePolicyManager dpm = getDevicePolicyManager();
    626             if (password != null) {
    627                 if (userHandle == UserHandle.USER_OWNER) {
    628                     // Update the encryption password.
    629                     updateEncryptionPassword(password);
    630                 }
    631 
    632                 int computedQuality = computePasswordQuality(password);
    633                 if (!isFallback) {
    634                     deleteGallery();
    635                     setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
    636                     if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    637                         int letters = 0;
    638                         int uppercase = 0;
    639                         int lowercase = 0;
    640                         int numbers = 0;
    641                         int symbols = 0;
    642                         int nonletter = 0;
    643                         for (int i = 0; i < password.length(); i++) {
    644                             char c = password.charAt(i);
    645                             if (c >= 'A' && c <= 'Z') {
    646                                 letters++;
    647                                 uppercase++;
    648                             } else if (c >= 'a' && c <= 'z') {
    649                                 letters++;
    650                                 lowercase++;
    651                             } else if (c >= '0' && c <= '9') {
    652                                 numbers++;
    653                                 nonletter++;
    654                             } else {
    655                                 symbols++;
    656                                 nonletter++;
    657                             }
    658                         }
    659                         dpm.setActivePasswordState(Math.max(quality, computedQuality),
    660                                 password.length(), letters, uppercase, lowercase,
    661                                 numbers, symbols, nonletter, userHandle);
    662                     } else {
    663                         // The password is not anything.
    664                         dpm.setActivePasswordState(
    665                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    666                                 0, 0, 0, 0, 0, 0, 0, userHandle);
    667                     }
    668                 } else {
    669                     // Case where it's a fallback for biometric weak
    670                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
    671                             userHandle);
    672                     setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
    673                             userHandle);
    674                     finishBiometricWeak();
    675                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
    676                             0, 0, 0, 0, 0, 0, 0, userHandle);
    677                 }
    678                 // Add the password to the password history. We assume all
    679                 // password
    680                 // hashes have the same length for simplicity of implementation.
    681                 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
    682                 if (passwordHistory == null) {
    683                     passwordHistory = new String();
    684                 }
    685                 int passwordHistoryLength = getRequestedPasswordHistoryLength();
    686                 if (passwordHistoryLength == 0) {
    687                     passwordHistory = "";
    688                 } else {
    689                     byte[] hash = passwordToHash(password);
    690                     passwordHistory = new String(hash) + "," + passwordHistory;
    691                     // Cut it to contain passwordHistoryLength hashes
    692                     // and passwordHistoryLength -1 commas.
    693                     passwordHistory = passwordHistory.substring(0, Math.min(hash.length
    694                             * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
    695                             .length()));
    696                 }
    697                 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
    698             } else {
    699                 dpm.setActivePasswordState(
    700                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
    701                         userHandle);
    702             }
    703         } catch (RemoteException re) {
    704             // Cant do much
    705             Log.e(TAG, "Unable to save lock password " + re);
    706         }
    707     }
    708 
    709     /**
    710      * Retrieves the quality mode we're in.
    711      * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
    712      *
    713      * @return stored password quality
    714      */
    715     public int getKeyguardStoredPasswordQuality() {
    716         int quality =
    717                 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    718         // If the user has chosen to use weak biometric sensor, then return the backup locking
    719         // method and treat biometric as a special case.
    720         if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
    721             quality =
    722                 (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
    723                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    724         }
    725         return quality;
    726     }
    727 
    728     /**
    729      * @return true if the lockscreen method is set to biometric weak
    730      */
    731     public boolean usingBiometricWeak() {
    732         int quality =
    733                 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    734         return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
    735     }
    736 
    737     /**
    738      * Deserialize a pattern.
    739      * @param string The pattern serialized with {@link #patternToString}
    740      * @return The pattern.
    741      */
    742     public static List<LockPatternView.Cell> stringToPattern(String string) {
    743         List<LockPatternView.Cell> result = Lists.newArrayList();
    744 
    745         final byte[] bytes = string.getBytes();
    746         for (int i = 0; i < bytes.length; i++) {
    747             byte b = bytes[i];
    748             result.add(LockPatternView.Cell.of(b / 3, b % 3));
    749         }
    750         return result;
    751     }
    752 
    753     /**
    754      * Serialize a pattern.
    755      * @param pattern The pattern.
    756      * @return The pattern in string form.
    757      */
    758     public static String patternToString(List<LockPatternView.Cell> pattern) {
    759         if (pattern == null) {
    760             return "";
    761         }
    762         final int patternSize = pattern.size();
    763 
    764         byte[] res = new byte[patternSize];
    765         for (int i = 0; i < patternSize; i++) {
    766             LockPatternView.Cell cell = pattern.get(i);
    767             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
    768         }
    769         return new String(res);
    770     }
    771 
    772     /*
    773      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
    774      * at least a second level of protection. First level is that the file
    775      * is in a location only readable by the system process.
    776      * @param pattern the gesture pattern.
    777      * @return the hash of the pattern in a byte array.
    778      */
    779     public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
    780         if (pattern == null) {
    781             return null;
    782         }
    783 
    784         final int patternSize = pattern.size();
    785         byte[] res = new byte[patternSize];
    786         for (int i = 0; i < patternSize; i++) {
    787             LockPatternView.Cell cell = pattern.get(i);
    788             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
    789         }
    790         try {
    791             MessageDigest md = MessageDigest.getInstance("SHA-1");
    792             byte[] hash = md.digest(res);
    793             return hash;
    794         } catch (NoSuchAlgorithmException nsa) {
    795             return res;
    796         }
    797     }
    798 
    799     private String getSalt() {
    800         long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
    801         if (salt == 0) {
    802             try {
    803                 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
    804                 setLong(LOCK_PASSWORD_SALT_KEY, salt);
    805                 Log.v(TAG, "Initialized lock password salt");
    806             } catch (NoSuchAlgorithmException e) {
    807                 // Throw an exception rather than storing a password we'll never be able to recover
    808                 throw new IllegalStateException("Couldn't get SecureRandom number", e);
    809             }
    810         }
    811         return Long.toHexString(salt);
    812     }
    813 
    814     /*
    815      * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
    816      * Not the most secure, but it is at least a second level of protection. First level is that
    817      * the file is in a location only readable by the system process.
    818      * @param password the gesture pattern.
    819      * @return the hash of the pattern in a byte array.
    820      */
    821     public byte[] passwordToHash(String password) {
    822         if (password == null) {
    823             return null;
    824         }
    825         String algo = null;
    826         byte[] hashed = null;
    827         try {
    828             byte[] saltedPassword = (password + getSalt()).getBytes();
    829             byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
    830             byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
    831             hashed = (toHex(sha1) + toHex(md5)).getBytes();
    832         } catch (NoSuchAlgorithmException e) {
    833             Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
    834         }
    835         return hashed;
    836     }
    837 
    838     private static String toHex(byte[] ary) {
    839         final String hex = "0123456789ABCDEF";
    840         String ret = "";
    841         for (int i = 0; i < ary.length; i++) {
    842             ret += hex.charAt((ary[i] >> 4) & 0xf);
    843             ret += hex.charAt(ary[i] & 0xf);
    844         }
    845         return ret;
    846     }
    847 
    848     /**
    849      * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
    850      */
    851     public boolean isLockPasswordEnabled() {
    852         long mode = getLong(PASSWORD_TYPE_KEY, 0);
    853         long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
    854         final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
    855                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
    856                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
    857                 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
    858         final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
    859                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
    860                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
    861                 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
    862 
    863         return savedPasswordExists() && (passwordEnabled ||
    864                 (usingBiometricWeak() && backupEnabled));
    865     }
    866 
    867     /**
    868      * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
    869      */
    870     public boolean isLockPatternEnabled() {
    871         final boolean backupEnabled =
    872                 getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
    873                 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
    874 
    875         return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
    876                 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
    877                         == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
    878                         (usingBiometricWeak() && backupEnabled));
    879     }
    880 
    881     /**
    882      * @return Whether biometric weak lock is installed and that the front facing camera exists
    883      */
    884     public boolean isBiometricWeakInstalled() {
    885         // Check that it's installed
    886         PackageManager pm = mContext.getPackageManager();
    887         try {
    888             pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
    889         } catch (PackageManager.NameNotFoundException e) {
    890             return false;
    891         }
    892 
    893         // Check that the camera is enabled
    894         if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
    895             return false;
    896         }
    897         if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
    898             return false;
    899         }
    900 
    901 
    902         return true;
    903     }
    904 
    905     /**
    906      * Set whether biometric weak liveliness is enabled.
    907      */
    908     public void setBiometricWeakLivelinessEnabled(boolean enabled) {
    909         long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
    910         long newFlag;
    911         if (enabled) {
    912             newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
    913         } else {
    914             newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
    915         }
    916         setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
    917     }
    918 
    919     /**
    920      * @return Whether the biometric weak liveliness is enabled.
    921      */
    922     public boolean isBiometricWeakLivelinessEnabled() {
    923         long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
    924         return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
    925     }
    926 
    927     /**
    928      * Set whether the lock pattern is enabled.
    929      */
    930     public void setLockPatternEnabled(boolean enabled) {
    931         setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
    932     }
    933 
    934     /**
    935      * @return Whether the visible pattern is enabled.
    936      */
    937     public boolean isVisiblePatternEnabled() {
    938         return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
    939     }
    940 
    941     /**
    942      * Set whether the visible pattern is enabled.
    943      */
    944     public void setVisiblePatternEnabled(boolean enabled) {
    945         setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
    946     }
    947 
    948     /**
    949      * @return Whether tactile feedback for the pattern is enabled.
    950      */
    951     public boolean isTactileFeedbackEnabled() {
    952         return Settings.System.getIntForUser(mContentResolver,
    953                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
    954     }
    955 
    956     /**
    957      * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
    958      * pattern until the deadline has passed.
    959      * @return the chosen deadline.
    960      */
    961     public long setLockoutAttemptDeadline() {
    962         final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
    963         setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
    964         return deadline;
    965     }
    966 
    967     /**
    968      * @return The elapsed time in millis in the future when the user is allowed to
    969      *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
    970      *   enter a pattern.
    971      */
    972     public long getLockoutAttemptDeadline() {
    973         final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
    974         final long now = SystemClock.elapsedRealtime();
    975         if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
    976             return 0L;
    977         }
    978         return deadline;
    979     }
    980 
    981     /**
    982      * @return Whether the user is permanently locked out until they verify their
    983      *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
    984      *   attempts.
    985      */
    986     public boolean isPermanentlyLocked() {
    987         return getBoolean(LOCKOUT_PERMANENT_KEY, false);
    988     }
    989 
    990     /**
    991      * Set the state of whether the device is permanently locked, meaning the user
    992      * must authenticate via other means.
    993      *
    994      * @param locked Whether the user is permanently locked out until they verify their
    995      *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
    996      *   attempts.
    997      */
    998     public void setPermanentlyLocked(boolean locked) {
    999         setBoolean(LOCKOUT_PERMANENT_KEY, locked);
   1000     }
   1001 
   1002     public boolean isEmergencyCallCapable() {
   1003         return mContext.getResources().getBoolean(
   1004                 com.android.internal.R.bool.config_voice_capable);
   1005     }
   1006 
   1007     public boolean isPukUnlockScreenEnable() {
   1008         return mContext.getResources().getBoolean(
   1009                 com.android.internal.R.bool.config_enable_puk_unlock_screen);
   1010     }
   1011 
   1012     public boolean isEmergencyCallEnabledWhileSimLocked() {
   1013         return mContext.getResources().getBoolean(
   1014                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
   1015     }
   1016 
   1017     /**
   1018      * @return A formatted string of the next alarm (for showing on the lock screen),
   1019      *   or null if there is no next alarm.
   1020      */
   1021     public String getNextAlarm() {
   1022         String nextAlarm = Settings.System.getStringForUser(mContentResolver,
   1023                 Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT);
   1024         if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
   1025             return null;
   1026         }
   1027         return nextAlarm;
   1028     }
   1029 
   1030     private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
   1031         try {
   1032             return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
   1033         } catch (RemoteException re) {
   1034             return defaultValue;
   1035         }
   1036     }
   1037 
   1038     private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
   1039         return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
   1040     }
   1041 
   1042     private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
   1043         try {
   1044             getLockSettings().setBoolean(secureSettingKey, enabled, userId);
   1045         } catch (RemoteException re) {
   1046             // What can we do?
   1047             Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
   1048         }
   1049     }
   1050 
   1051     private void setBoolean(String secureSettingKey, boolean enabled) {
   1052         setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
   1053     }
   1054 
   1055     public int[] getAppWidgets() {
   1056         return getAppWidgets(UserHandle.USER_CURRENT);
   1057     }
   1058 
   1059     private int[] getAppWidgets(int userId) {
   1060         String appWidgetIdString = Settings.Secure.getStringForUser(
   1061                 mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
   1062         String delims = ",";
   1063         if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
   1064             String[] appWidgetStringIds = appWidgetIdString.split(delims);
   1065             int[] appWidgetIds = new int[appWidgetStringIds.length];
   1066             for (int i = 0; i < appWidgetStringIds.length; i++) {
   1067                 String appWidget = appWidgetStringIds[i];
   1068                 try {
   1069                     appWidgetIds[i] = Integer.decode(appWidget);
   1070                 } catch (NumberFormatException e) {
   1071                     Log.d(TAG, "Error when parsing widget id " + appWidget);
   1072                     return null;
   1073                 }
   1074             }
   1075             return appWidgetIds;
   1076         }
   1077         return new int[0];
   1078     }
   1079 
   1080     private static String combineStrings(int[] list, String separator) {
   1081         int listLength = list.length;
   1082 
   1083         switch (listLength) {
   1084             case 0: {
   1085                 return "";
   1086             }
   1087             case 1: {
   1088                 return Integer.toString(list[0]);
   1089             }
   1090         }
   1091 
   1092         int strLength = 0;
   1093         int separatorLength = separator.length();
   1094 
   1095         String[] stringList = new String[list.length];
   1096         for (int i = 0; i < listLength; i++) {
   1097             stringList[i] = Integer.toString(list[i]);
   1098             strLength += stringList[i].length();
   1099             if (i < listLength - 1) {
   1100                 strLength += separatorLength;
   1101             }
   1102         }
   1103 
   1104         StringBuilder sb = new StringBuilder(strLength);
   1105 
   1106         for (int i = 0; i < listLength; i++) {
   1107             sb.append(list[i]);
   1108             if (i < listLength - 1) {
   1109                 sb.append(separator);
   1110             }
   1111         }
   1112 
   1113         return sb.toString();
   1114     }
   1115 
   1116     // appwidget used when appwidgets are disabled (we make an exception for
   1117     // default clock widget)
   1118     public void writeFallbackAppWidgetId(int appWidgetId) {
   1119         Settings.Secure.putIntForUser(mContentResolver,
   1120                 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
   1121                 appWidgetId,
   1122                 UserHandle.USER_CURRENT);
   1123     }
   1124 
   1125     // appwidget used when appwidgets are disabled (we make an exception for
   1126     // default clock widget)
   1127     public int getFallbackAppWidgetId() {
   1128         return Settings.Secure.getIntForUser(
   1129                 mContentResolver,
   1130                 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
   1131                 AppWidgetManager.INVALID_APPWIDGET_ID,
   1132                 UserHandle.USER_CURRENT);
   1133     }
   1134 
   1135     private void writeAppWidgets(int[] appWidgetIds) {
   1136         Settings.Secure.putStringForUser(mContentResolver,
   1137                         Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
   1138                         combineStrings(appWidgetIds, ","),
   1139                         UserHandle.USER_CURRENT);
   1140     }
   1141 
   1142     // TODO: log an error if this returns false
   1143     public boolean addAppWidget(int widgetId, int index) {
   1144         int[] widgets = getAppWidgets();
   1145         if (widgets == null) {
   1146             return false;
   1147         }
   1148         if (index < 0 || index > widgets.length) {
   1149             return false;
   1150         }
   1151         int[] newWidgets = new int[widgets.length + 1];
   1152         for (int i = 0, j = 0; i < newWidgets.length; i++) {
   1153             if (index == i) {
   1154                 newWidgets[i] = widgetId;
   1155                 i++;
   1156             }
   1157             if (i < newWidgets.length) {
   1158                 newWidgets[i] = widgets[j];
   1159                 j++;
   1160             }
   1161         }
   1162         writeAppWidgets(newWidgets);
   1163         return true;
   1164     }
   1165 
   1166     public boolean removeAppWidget(int widgetId) {
   1167         int[] widgets = getAppWidgets();
   1168 
   1169         if (widgets.length == 0) {
   1170             return false;
   1171         }
   1172 
   1173         int[] newWidgets = new int[widgets.length - 1];
   1174         for (int i = 0, j = 0; i < widgets.length; i++) {
   1175             if (widgets[i] == widgetId) {
   1176                 // continue...
   1177             } else if (j >= newWidgets.length) {
   1178                 // we couldn't find the widget
   1179                 return false;
   1180             } else {
   1181                 newWidgets[j] = widgets[i];
   1182                 j++;
   1183             }
   1184         }
   1185         writeAppWidgets(newWidgets);
   1186         return true;
   1187     }
   1188 
   1189     private long getLong(String secureSettingKey, long defaultValue) {
   1190         try {
   1191             return getLockSettings().getLong(secureSettingKey, defaultValue,
   1192                     getCurrentOrCallingUserId());
   1193         } catch (RemoteException re) {
   1194             return defaultValue;
   1195         }
   1196     }
   1197 
   1198     private void setLong(String secureSettingKey, long value) {
   1199         setLong(secureSettingKey, value, getCurrentOrCallingUserId());
   1200     }
   1201 
   1202     private void setLong(String secureSettingKey, long value, int userHandle) {
   1203         try {
   1204             getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId());
   1205         } catch (RemoteException re) {
   1206             // What can we do?
   1207             Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
   1208         }
   1209     }
   1210 
   1211     private String getString(String secureSettingKey) {
   1212         return getString(secureSettingKey, getCurrentOrCallingUserId());
   1213     }
   1214 
   1215     private String getString(String secureSettingKey, int userHandle) {
   1216         try {
   1217             return getLockSettings().getString(secureSettingKey, null, userHandle);
   1218         } catch (RemoteException re) {
   1219             return null;
   1220         }
   1221     }
   1222 
   1223     private void setString(String secureSettingKey, String value, int userHandle) {
   1224         try {
   1225             getLockSettings().setString(secureSettingKey, value, userHandle);
   1226         } catch (RemoteException re) {
   1227             // What can we do?
   1228             Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
   1229         }
   1230     }
   1231 
   1232     public boolean isSecure() {
   1233         long mode = getKeyguardStoredPasswordQuality();
   1234         final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
   1235         final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
   1236                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
   1237                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
   1238                 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
   1239         final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
   1240                 || isPassword && savedPasswordExists();
   1241         return secure;
   1242     }
   1243 
   1244     /**
   1245      * Sets the emergency button visibility based on isEmergencyCallCapable().
   1246      *
   1247      * If the emergency button is visible, sets the text on the emergency button
   1248      * to indicate what action will be taken.
   1249      *
   1250      * If there's currently a call in progress, the button will take them to the call
   1251      * @param button the button to update
   1252      * @param the phone state:
   1253      *  {@link TelephonyManager#CALL_STATE_IDLE}
   1254      *  {@link TelephonyManager#CALL_STATE_RINGING}
   1255      *  {@link TelephonyManager#CALL_STATE_OFFHOOK}
   1256      * @param shown indicates whether the given screen wants the emergency button to show at all
   1257      * @param button
   1258      * @param phoneState
   1259      * @param shown shown if true; hidden if false
   1260      * @param upperCase if true, converts button label string to upper case
   1261      */
   1262     public void updateEmergencyCallButtonState(Button button, int  phoneState, boolean shown,
   1263             boolean showIcon) {
   1264         if (isEmergencyCallCapable() && shown) {
   1265             button.setVisibility(View.VISIBLE);
   1266         } else {
   1267             button.setVisibility(View.GONE);
   1268             return;
   1269         }
   1270 
   1271         int textId;
   1272         if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
   1273             // show "return to call" text and show phone icon
   1274             textId = R.string.lockscreen_return_to_call;
   1275             int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
   1276             button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
   1277         } else {
   1278             textId = R.string.lockscreen_emergency_call;
   1279             int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
   1280             button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
   1281         }
   1282         button.setText(textId);
   1283     }
   1284 
   1285     /**
   1286      * Resumes a call in progress. Typically launched from the EmergencyCall button
   1287      * on various lockscreens.
   1288      *
   1289      * @return true if we were able to tell InCallScreen to show.
   1290      */
   1291     public boolean resumeCall() {
   1292         ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
   1293         try {
   1294             if (phone != null && phone.showCallScreen()) {
   1295                 return true;
   1296             }
   1297         } catch (RemoteException e) {
   1298             // What can we do?
   1299         }
   1300         return false;
   1301     }
   1302 
   1303     private void finishBiometricWeak() {
   1304         setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
   1305 
   1306         // Launch intent to show final screen, this also
   1307         // moves the temporary gallery to the actual gallery
   1308         Intent intent = new Intent();
   1309         intent.setClassName("com.android.facelock",
   1310                 "com.android.facelock.SetupEndScreen");
   1311         mContext.startActivity(intent);
   1312     }
   1313 
   1314     public void setPowerButtonInstantlyLocks(boolean enabled) {
   1315         setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
   1316     }
   1317 
   1318     public boolean getPowerButtonInstantlyLocks() {
   1319         return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
   1320     }
   1321 
   1322     public static boolean isSafeModeEnabled() {
   1323         try {
   1324             return IWindowManager.Stub.asInterface(
   1325                     ServiceManager.getService("window")).isSafeModeEnabled();
   1326         } catch (RemoteException e) {
   1327             // Shouldn't happen!
   1328         }
   1329         return false;
   1330     }
   1331 
   1332     /**
   1333      * Determine whether the user has selected any non-system widgets in keyguard
   1334      *
   1335      * @return true if widgets have been selected
   1336      */
   1337     public boolean hasWidgetsEnabledInKeyguard(int userid) {
   1338         int widgets[] = getAppWidgets(userid);
   1339         for (int i = 0; i < widgets.length; i++) {
   1340             if (widgets[i] > 0) {
   1341                 return true;
   1342             }
   1343         }
   1344         return false;
   1345     }
   1346 
   1347     public boolean getWidgetsEnabled() {
   1348         return getWidgetsEnabled(getCurrentOrCallingUserId());
   1349     }
   1350 
   1351     public boolean getWidgetsEnabled(int userId) {
   1352         return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
   1353     }
   1354 
   1355     public void setWidgetsEnabled(boolean enabled) {
   1356         setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
   1357     }
   1358 
   1359     public void setWidgetsEnabled(boolean enabled, int userId) {
   1360         setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
   1361     }
   1362 
   1363 }
   1364