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