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