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