LockPatternUtils.java revision dd5de719c5a0d39030f94d931c0ab1bed1f147f8
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 boolean required = isCredentialRequiredToDecrypt(true);
564                    if (!required) {
565                        clearEncryptionPassword();
566                    } else {
567                        String stringPattern = patternToString(pattern);
568                        updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
569                    }
570                }
571
572                setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
573                if (!isFallback) {
574                    deleteGallery();
575                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
576                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
577                            pattern.size(), 0, 0, 0, 0, 0, 0, userId);
578                } else {
579                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
580                    setLong(PASSWORD_TYPE_ALTERNATE_KEY,
581                            DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
582                    finishBiometricWeak();
583                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
584                            0, 0, 0, 0, 0, 0, 0, userId);
585                }
586            } else {
587                dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
588                        0, 0, 0, 0, 0, userId);
589            }
590            onAfterChangingPassword();
591        } catch (RemoteException re) {
592            Log.e(TAG, "Couldn't save lock pattern " + re);
593        }
594    }
595
596    private void updateCryptoUserInfo() {
597        int userId = getCurrentOrCallingUserId();
598        if (userId != UserHandle.USER_OWNER) {
599            return;
600        }
601
602        final String ownerInfo = isOwnerInfoEnabled() ? getOwnerInfo(userId) : "";
603
604        IBinder service = ServiceManager.getService("mount");
605        if (service == null) {
606            Log.e(TAG, "Could not find the mount service to update the user info");
607            return;
608        }
609
610        IMountService mountService = IMountService.Stub.asInterface(service);
611        try {
612            Log.d(TAG, "Setting owner info");
613            mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
614        } catch (RemoteException e) {
615            Log.e(TAG, "Error changing user info", e);
616        }
617    }
618
619    public void setOwnerInfo(String info, int userId) {
620        setString(LOCK_SCREEN_OWNER_INFO, info, userId);
621        updateCryptoUserInfo();
622    }
623
624    public void setOwnerInfoEnabled(boolean enabled) {
625        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
626        updateCryptoUserInfo();
627    }
628
629    public String getOwnerInfo(int userId) {
630        return getString(LOCK_SCREEN_OWNER_INFO);
631    }
632
633    public boolean isOwnerInfoEnabled() {
634        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
635    }
636
637    /**
638     * Compute the password quality from the given password string.
639     */
640    static public int computePasswordQuality(String password) {
641        boolean hasDigit = false;
642        boolean hasNonDigit = false;
643        final int len = password.length();
644        for (int i = 0; i < len; i++) {
645            if (Character.isDigit(password.charAt(i))) {
646                hasDigit = true;
647            } else {
648                hasNonDigit = true;
649            }
650        }
651
652        if (hasNonDigit && hasDigit) {
653            return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
654        }
655        if (hasNonDigit) {
656            return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
657        }
658        if (hasDigit) {
659            return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
660                    ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
661                    : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
662        }
663        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
664    }
665
666    private static int categoryChar(char c) {
667        if ('a' <= c && c <= 'z') return 0;
668        if ('A' <= c && c <= 'Z') return 1;
669        if ('0' <= c && c <= '9') return 2;
670        return 3;
671    }
672
673    private static int maxDiffCategory(int category) {
674        if (category == 0 || category == 1) return 1;
675        else if (category == 2) return 10;
676        return 0;
677    }
678
679    /*
680     * Returns the maximum length of a sequential characters.  A sequence is defined as
681     * monotonically increasing characters with a constant interval or the same character repeated.
682     *
683     * For example:
684     * maxLengthSequence("1234") == 4
685     * maxLengthSequence("1234abc") == 4
686     * maxLengthSequence("aabc") == 3
687     * maxLengthSequence("qwertyuio") == 1
688     * maxLengthSequence("@ABC") == 3
689     * maxLengthSequence(";;;;") == 4 (anything that repeats)
690     * maxLengthSequence(":;<=>") == 1  (ordered, but not composed of alphas or digits)
691     *
692     * @param string the pass
693     * @return the number of sequential letters or digits
694     */
695    public static int maxLengthSequence(String string) {
696        if (string.length() == 0) return 0;
697        char previousChar = string.charAt(0);
698        int category = categoryChar(previousChar); //current category of the sequence
699        int diff = 0; //difference between two consecutive characters
700        boolean hasDiff = false; //if we are currently targeting a sequence
701        int maxLength = 0; //maximum length of a sequence already found
702        int startSequence = 0; //where the current sequence started
703        for (int current = 1; current < string.length(); current++) {
704            char currentChar = string.charAt(current);
705            int categoryCurrent = categoryChar(currentChar);
706            int currentDiff = (int) currentChar - (int) previousChar;
707            if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
708                maxLength = Math.max(maxLength, current - startSequence);
709                startSequence = current;
710                hasDiff = false;
711                category = categoryCurrent;
712            }
713            else {
714                if(hasDiff && currentDiff != diff) {
715                    maxLength = Math.max(maxLength, current - startSequence);
716                    startSequence = current - 1;
717                }
718                diff = currentDiff;
719                hasDiff = true;
720            }
721            previousChar = currentChar;
722        }
723        maxLength = Math.max(maxLength, string.length() - startSequence);
724        return maxLength;
725    }
726
727    /** Update the encryption password if it is enabled **/
728    private void updateEncryptionPassword(final int type, final String password) {
729        if (!isDeviceEncryptionEnabled()) {
730            return;
731        }
732        final IBinder service = ServiceManager.getService("mount");
733        if (service == null) {
734            Log.e(TAG, "Could not find the mount service to update the encryption password");
735            return;
736        }
737
738        new AsyncTask<Void, Void, Void>() {
739            @Override
740            protected Void doInBackground(Void... dummy) {
741                IMountService mountService = IMountService.Stub.asInterface(service);
742                try {
743                    mountService.changeEncryptionPassword(type, password);
744                } catch (RemoteException e) {
745                    Log.e(TAG, "Error changing encryption password", e);
746                }
747                return null;
748            }
749        }.execute();
750    }
751
752    /**
753     * Save a lock password.  Does not ensure that the password is as good
754     * as the requested mode, but will adjust the mode to be as good as the
755     * pattern.
756     * @param password The password to save
757     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
758     */
759    public void saveLockPassword(String password, int quality) {
760        this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
761    }
762
763    /**
764     * Save a lock password.  Does not ensure that the password is as good
765     * as the requested mode, but will adjust the mode to be as good as the
766     * pattern.
767     * @param password The password to save
768     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
769     * @param isFallback Specifies if this is a fallback to biometric weak
770     */
771    public void saveLockPassword(String password, int quality, boolean isFallback) {
772        saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
773    }
774
775    /**
776     * Save a lock password.  Does not ensure that the password is as good
777     * as the requested mode, but will adjust the mode to be as good as the
778     * pattern.
779     * @param password The password to save
780     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
781     * @param isFallback Specifies if this is a fallback to biometric weak
782     * @param userHandle The userId of the user to change the password for
783     */
784    public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
785        try {
786            DevicePolicyManager dpm = getDevicePolicyManager();
787            if (!TextUtils.isEmpty(password)) {
788                getLockSettings().setLockPassword(password, userHandle);
789                int computedQuality = computePasswordQuality(password);
790
791                // Update the device encryption password.
792                if (userHandle == UserHandle.USER_OWNER
793                        && LockPatternUtils.isDeviceEncryptionEnabled()) {
794                    if (!isCredentialRequiredToDecrypt(true)) {
795                        clearEncryptionPassword();
796                    } else {
797                        boolean numeric = computedQuality
798                                == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
799                        boolean numericComplex = computedQuality
800                                == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
801                        int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
802                                : StorageManager.CRYPT_TYPE_PASSWORD;
803                        updateEncryptionPassword(type, password);
804                    }
805                }
806
807                if (!isFallback) {
808                    deleteGallery();
809                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
810                    if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
811                        int letters = 0;
812                        int uppercase = 0;
813                        int lowercase = 0;
814                        int numbers = 0;
815                        int symbols = 0;
816                        int nonletter = 0;
817                        for (int i = 0; i < password.length(); i++) {
818                            char c = password.charAt(i);
819                            if (c >= 'A' && c <= 'Z') {
820                                letters++;
821                                uppercase++;
822                            } else if (c >= 'a' && c <= 'z') {
823                                letters++;
824                                lowercase++;
825                            } else if (c >= '0' && c <= '9') {
826                                numbers++;
827                                nonletter++;
828                            } else {
829                                symbols++;
830                                nonletter++;
831                            }
832                        }
833                        dpm.setActivePasswordState(Math.max(quality, computedQuality),
834                                password.length(), letters, uppercase, lowercase,
835                                numbers, symbols, nonletter, userHandle);
836                    } else {
837                        // The password is not anything.
838                        dpm.setActivePasswordState(
839                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
840                                0, 0, 0, 0, 0, 0, 0, userHandle);
841                    }
842                } else {
843                    // Case where it's a fallback for biometric weak
844                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
845                            userHandle);
846                    setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
847                            userHandle);
848                    finishBiometricWeak();
849                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
850                            0, 0, 0, 0, 0, 0, 0, userHandle);
851                }
852                // Add the password to the password history. We assume all
853                // password hashes have the same length for simplicity of implementation.
854                String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
855                if (passwordHistory == null) {
856                    passwordHistory = new String();
857                }
858                int passwordHistoryLength = getRequestedPasswordHistoryLength();
859                if (passwordHistoryLength == 0) {
860                    passwordHistory = "";
861                } else {
862                    byte[] hash = passwordToHash(password, userHandle);
863                    passwordHistory = new String(hash) + "," + passwordHistory;
864                    // Cut it to contain passwordHistoryLength hashes
865                    // and passwordHistoryLength -1 commas.
866                    passwordHistory = passwordHistory.substring(0, Math.min(hash.length
867                            * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
868                            .length()));
869                }
870                setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
871            } else {
872                // Empty password
873                getLockSettings().setLockPassword(null, userHandle);
874                if (userHandle == UserHandle.USER_OWNER) {
875                    // Set the encryption password to default.
876                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
877                }
878
879                dpm.setActivePasswordState(
880                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
881                        userHandle);
882            }
883            onAfterChangingPassword();
884        } catch (RemoteException re) {
885            // Cant do much
886            Log.e(TAG, "Unable to save lock password " + re);
887        }
888    }
889
890    /**
891     * Gets whether the device is encrypted.
892     *
893     * @return Whether the device is encrypted.
894     */
895    public static boolean isDeviceEncrypted() {
896        IMountService mountService = IMountService.Stub.asInterface(
897                ServiceManager.getService("mount"));
898        try {
899            return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
900                    && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
901        } catch (RemoteException re) {
902            Log.e(TAG, "Error getting encryption state", re);
903        }
904        return true;
905    }
906
907    /**
908     * Determine if the device supports encryption, even if it's set to default. This
909     * differs from isDeviceEncrypted() in that it returns true even if the device is
910     * encrypted with the default password.
911     * @return true if device encryption is enabled
912     */
913    public static boolean isDeviceEncryptionEnabled() {
914        final String status = SystemProperties.get("ro.crypto.state", "unsupported");
915        return "encrypted".equalsIgnoreCase(status);
916    }
917
918    /**
919     * Clears the encryption password.
920     */
921    public void clearEncryptionPassword() {
922        updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
923    }
924
925    /**
926     * Retrieves the quality mode we're in.
927     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
928     *
929     * @return stored password quality
930     */
931    public int getKeyguardStoredPasswordQuality() {
932        return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId());
933    }
934
935    /**
936     * Retrieves the quality mode for {@param userHandle}.
937     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
938     *
939     * @return stored password quality
940     */
941    public int getKeyguardStoredPasswordQuality(int userHandle) {
942        int quality = (int) getLong(PASSWORD_TYPE_KEY,
943                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
944        // If the user has chosen to use weak biometric sensor, then return the backup locking
945        // method and treat biometric as a special case.
946        if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
947            quality = (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
948                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
949        }
950        return quality;
951    }
952
953    /**
954     * @return true if the lockscreen method is set to biometric weak
955     */
956    public boolean usingBiometricWeak() {
957        int quality =
958                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
959        return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
960    }
961
962    /**
963     * Deserialize a pattern.
964     * @param string The pattern serialized with {@link #patternToString}
965     * @return The pattern.
966     */
967    public static List<LockPatternView.Cell> stringToPattern(String string) {
968        List<LockPatternView.Cell> result = Lists.newArrayList();
969
970        final byte[] bytes = string.getBytes();
971        for (int i = 0; i < bytes.length; i++) {
972            byte b = bytes[i];
973            result.add(LockPatternView.Cell.of(b / 3, b % 3));
974        }
975        return result;
976    }
977
978    /**
979     * Serialize a pattern.
980     * @param pattern The pattern.
981     * @return The pattern in string form.
982     */
983    public static String patternToString(List<LockPatternView.Cell> pattern) {
984        if (pattern == null) {
985            return "";
986        }
987        final int patternSize = pattern.size();
988
989        byte[] res = new byte[patternSize];
990        for (int i = 0; i < patternSize; i++) {
991            LockPatternView.Cell cell = pattern.get(i);
992            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
993        }
994        return new String(res);
995    }
996
997    /*
998     * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
999     * at least a second level of protection. First level is that the file
1000     * is in a location only readable by the system process.
1001     * @param pattern the gesture pattern.
1002     * @return the hash of the pattern in a byte array.
1003     */
1004    public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
1005        if (pattern == null) {
1006            return null;
1007        }
1008
1009        final int patternSize = pattern.size();
1010        byte[] res = new byte[patternSize];
1011        for (int i = 0; i < patternSize; i++) {
1012            LockPatternView.Cell cell = pattern.get(i);
1013            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1014        }
1015        try {
1016            MessageDigest md = MessageDigest.getInstance("SHA-1");
1017            byte[] hash = md.digest(res);
1018            return hash;
1019        } catch (NoSuchAlgorithmException nsa) {
1020            return res;
1021        }
1022    }
1023
1024    private String getSalt(int userId) {
1025        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
1026        if (salt == 0) {
1027            try {
1028                salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
1029                setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1030                Log.v(TAG, "Initialized lock password salt for user: " + userId);
1031            } catch (NoSuchAlgorithmException e) {
1032                // Throw an exception rather than storing a password we'll never be able to recover
1033                throw new IllegalStateException("Couldn't get SecureRandom number", e);
1034            }
1035        }
1036        return Long.toHexString(salt);
1037    }
1038
1039    /*
1040     * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1041     * Not the most secure, but it is at least a second level of protection. First level is that
1042     * the file is in a location only readable by the system process.
1043     * @param password the gesture pattern.
1044     * @return the hash of the pattern in a byte array.
1045     */
1046    public byte[] passwordToHash(String password, int userId) {
1047        if (password == null) {
1048            return null;
1049        }
1050        String algo = null;
1051        byte[] hashed = null;
1052        try {
1053            byte[] saltedPassword = (password + getSalt(userId)).getBytes();
1054            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
1055            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
1056            hashed = (toHex(sha1) + toHex(md5)).getBytes();
1057        } catch (NoSuchAlgorithmException e) {
1058            Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
1059        }
1060        return hashed;
1061    }
1062
1063    private static String toHex(byte[] ary) {
1064        final String hex = "0123456789ABCDEF";
1065        String ret = "";
1066        for (int i = 0; i < ary.length; i++) {
1067            ret += hex.charAt((ary[i] >> 4) & 0xf);
1068            ret += hex.charAt(ary[i] & 0xf);
1069        }
1070        return ret;
1071    }
1072
1073    /**
1074     * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
1075     */
1076    public boolean isLockPasswordEnabled() {
1077        long mode = getLong(PASSWORD_TYPE_KEY, 0);
1078        long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
1079        final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1080                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1081                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
1082                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1083                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
1084        final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1085                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1086                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
1087                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1088                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
1089
1090        return savedPasswordExists() && (passwordEnabled ||
1091                (usingBiometricWeak() && backupEnabled));
1092    }
1093
1094    /**
1095     * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
1096     */
1097    public boolean isLockPatternEnabled() {
1098        final boolean backupEnabled =
1099                getLong(PASSWORD_TYPE_ALTERNATE_KEY,
1100                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)
1101                                == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1102
1103        return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
1104                && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)
1105                        == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
1106                        (usingBiometricWeak() && backupEnabled));
1107    }
1108
1109    /**
1110     * @return Whether biometric weak lock is installed and that the front facing camera exists
1111     */
1112    public boolean isBiometricWeakInstalled() {
1113        // Check that it's installed
1114        PackageManager pm = mContext.getPackageManager();
1115        try {
1116            pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
1117        } catch (PackageManager.NameNotFoundException e) {
1118            return false;
1119        }
1120
1121        // Check that the camera is enabled
1122        if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
1123            return false;
1124        }
1125        if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
1126            return false;
1127        }
1128
1129        // TODO: If we decide not to proceed with Face Unlock as a trustlet, this must be changed
1130        // back to returning true.  If we become certain that Face Unlock will be a trustlet, this
1131        // entire function and a lot of other code can be removed.
1132        if (DEBUG) Log.d(TAG, "Forcing isBiometricWeakInstalled() to return false to disable it");
1133        return false;
1134    }
1135
1136    /**
1137     * Set whether biometric weak liveliness is enabled.
1138     */
1139    public void setBiometricWeakLivelinessEnabled(boolean enabled) {
1140        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
1141        long newFlag;
1142        if (enabled) {
1143            newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
1144        } else {
1145            newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
1146        }
1147        setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
1148    }
1149
1150    /**
1151     * @return Whether the biometric weak liveliness is enabled.
1152     */
1153    public boolean isBiometricWeakLivelinessEnabled() {
1154        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
1155        return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
1156    }
1157
1158    /**
1159     * Set whether the lock pattern is enabled.
1160     */
1161    public void setLockPatternEnabled(boolean enabled) {
1162        setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
1163    }
1164
1165    /**
1166     * @return Whether the visible pattern is enabled.
1167     */
1168    public boolean isVisiblePatternEnabled() {
1169        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
1170    }
1171
1172    /**
1173     * Set whether the visible pattern is enabled.
1174     */
1175    public void setVisiblePatternEnabled(boolean enabled) {
1176        setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
1177
1178        // Update for crypto if owner
1179        int userId = getCurrentOrCallingUserId();
1180        if (userId != UserHandle.USER_OWNER) {
1181            return;
1182        }
1183
1184        IBinder service = ServiceManager.getService("mount");
1185        if (service == null) {
1186            Log.e(TAG, "Could not find the mount service to update the user info");
1187            return;
1188        }
1189
1190        IMountService mountService = IMountService.Stub.asInterface(service);
1191        try {
1192            mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
1193        } catch (RemoteException e) {
1194            Log.e(TAG, "Error changing pattern visible state", e);
1195        }
1196    }
1197
1198    /**
1199     * @return Whether tactile feedback for the pattern is enabled.
1200     */
1201    public boolean isTactileFeedbackEnabled() {
1202        return Settings.System.getIntForUser(mContentResolver,
1203                Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
1204    }
1205
1206    /**
1207     * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1208     * pattern until the deadline has passed.
1209     * @return the chosen deadline.
1210     */
1211    public long setLockoutAttemptDeadline() {
1212        final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
1213        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
1214        return deadline;
1215    }
1216
1217    /**
1218     * @return The elapsed time in millis in the future when the user is allowed to
1219     *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
1220     *   enter a pattern.
1221     */
1222    public long getLockoutAttemptDeadline() {
1223        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
1224        final long now = SystemClock.elapsedRealtime();
1225        if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
1226            return 0L;
1227        }
1228        return deadline;
1229    }
1230
1231    /**
1232     * @return Whether the user is permanently locked out until they verify their
1233     *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
1234     *   attempts.
1235     */
1236    public boolean isPermanentlyLocked() {
1237        return getBoolean(LOCKOUT_PERMANENT_KEY, false);
1238    }
1239
1240    /**
1241     * Set the state of whether the device is permanently locked, meaning the user
1242     * must authenticate via other means.
1243     *
1244     * @param locked Whether the user is permanently locked out until they verify their
1245     *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
1246     *   attempts.
1247     */
1248    public void setPermanentlyLocked(boolean locked) {
1249        setBoolean(LOCKOUT_PERMANENT_KEY, locked);
1250    }
1251
1252    public boolean isEmergencyCallCapable() {
1253        return mContext.getResources().getBoolean(
1254                com.android.internal.R.bool.config_voice_capable);
1255    }
1256
1257    public boolean isPukUnlockScreenEnable() {
1258        return mContext.getResources().getBoolean(
1259                com.android.internal.R.bool.config_enable_puk_unlock_screen);
1260    }
1261
1262    public boolean isEmergencyCallEnabledWhileSimLocked() {
1263        return mContext.getResources().getBoolean(
1264                com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
1265    }
1266
1267    /**
1268     * @return A formatted string of the next alarm (for showing on the lock screen),
1269     *   or null if there is no next alarm.
1270     */
1271    public AlarmManager.AlarmClockInfo getNextAlarm() {
1272        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
1273        return alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
1274    }
1275
1276    private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
1277        try {
1278            return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
1279        } catch (RemoteException re) {
1280            return defaultValue;
1281        }
1282    }
1283
1284    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
1285        return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
1286    }
1287
1288    private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
1289        try {
1290            getLockSettings().setBoolean(secureSettingKey, enabled, userId);
1291        } catch (RemoteException re) {
1292            // What can we do?
1293            Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1294        }
1295    }
1296
1297    private void setBoolean(String secureSettingKey, boolean enabled) {
1298        setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
1299    }
1300
1301    public int[] getAppWidgets() {
1302        return getAppWidgets(UserHandle.USER_CURRENT);
1303    }
1304
1305    private int[] getAppWidgets(int userId) {
1306        String appWidgetIdString = Settings.Secure.getStringForUser(
1307                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
1308        String delims = ",";
1309        if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
1310            String[] appWidgetStringIds = appWidgetIdString.split(delims);
1311            int[] appWidgetIds = new int[appWidgetStringIds.length];
1312            for (int i = 0; i < appWidgetStringIds.length; i++) {
1313                String appWidget = appWidgetStringIds[i];
1314                try {
1315                    appWidgetIds[i] = Integer.decode(appWidget);
1316                } catch (NumberFormatException e) {
1317                    Log.d(TAG, "Error when parsing widget id " + appWidget);
1318                    return null;
1319                }
1320            }
1321            return appWidgetIds;
1322        }
1323        return new int[0];
1324    }
1325
1326    private static String combineStrings(int[] list, String separator) {
1327        int listLength = list.length;
1328
1329        switch (listLength) {
1330            case 0: {
1331                return "";
1332            }
1333            case 1: {
1334                return Integer.toString(list[0]);
1335            }
1336        }
1337
1338        int strLength = 0;
1339        int separatorLength = separator.length();
1340
1341        String[] stringList = new String[list.length];
1342        for (int i = 0; i < listLength; i++) {
1343            stringList[i] = Integer.toString(list[i]);
1344            strLength += stringList[i].length();
1345            if (i < listLength - 1) {
1346                strLength += separatorLength;
1347            }
1348        }
1349
1350        StringBuilder sb = new StringBuilder(strLength);
1351
1352        for (int i = 0; i < listLength; i++) {
1353            sb.append(list[i]);
1354            if (i < listLength - 1) {
1355                sb.append(separator);
1356            }
1357        }
1358
1359        return sb.toString();
1360    }
1361
1362    // appwidget used when appwidgets are disabled (we make an exception for
1363    // default clock widget)
1364    public void writeFallbackAppWidgetId(int appWidgetId) {
1365        Settings.Secure.putIntForUser(mContentResolver,
1366                Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1367                appWidgetId,
1368                UserHandle.USER_CURRENT);
1369    }
1370
1371    // appwidget used when appwidgets are disabled (we make an exception for
1372    // default clock widget)
1373    public int getFallbackAppWidgetId() {
1374        return Settings.Secure.getIntForUser(
1375                mContentResolver,
1376                Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1377                AppWidgetManager.INVALID_APPWIDGET_ID,
1378                UserHandle.USER_CURRENT);
1379    }
1380
1381    private void writeAppWidgets(int[] appWidgetIds) {
1382        Settings.Secure.putStringForUser(mContentResolver,
1383                        Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
1384                        combineStrings(appWidgetIds, ","),
1385                        UserHandle.USER_CURRENT);
1386    }
1387
1388    // TODO: log an error if this returns false
1389    public boolean addAppWidget(int widgetId, int index) {
1390        int[] widgets = getAppWidgets();
1391        if (widgets == null) {
1392            return false;
1393        }
1394        if (index < 0 || index > widgets.length) {
1395            return false;
1396        }
1397        int[] newWidgets = new int[widgets.length + 1];
1398        for (int i = 0, j = 0; i < newWidgets.length; i++) {
1399            if (index == i) {
1400                newWidgets[i] = widgetId;
1401                i++;
1402            }
1403            if (i < newWidgets.length) {
1404                newWidgets[i] = widgets[j];
1405                j++;
1406            }
1407        }
1408        writeAppWidgets(newWidgets);
1409        return true;
1410    }
1411
1412    public boolean removeAppWidget(int widgetId) {
1413        int[] widgets = getAppWidgets();
1414
1415        if (widgets.length == 0) {
1416            return false;
1417        }
1418
1419        int[] newWidgets = new int[widgets.length - 1];
1420        for (int i = 0, j = 0; i < widgets.length; i++) {
1421            if (widgets[i] == widgetId) {
1422                // continue...
1423            } else if (j >= newWidgets.length) {
1424                // we couldn't find the widget
1425                return false;
1426            } else {
1427                newWidgets[j] = widgets[i];
1428                j++;
1429            }
1430        }
1431        writeAppWidgets(newWidgets);
1432        return true;
1433    }
1434
1435    private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1436        try {
1437            return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1438        } catch (RemoteException re) {
1439            return defaultValue;
1440        }
1441    }
1442
1443    private long getLong(String secureSettingKey, long defaultValue) {
1444        try {
1445            return getLockSettings().getLong(secureSettingKey, defaultValue,
1446                    getCurrentOrCallingUserId());
1447        } catch (RemoteException re) {
1448            return defaultValue;
1449        }
1450    }
1451
1452    private void setLong(String secureSettingKey, long value) {
1453        setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1454    }
1455
1456    private void setLong(String secureSettingKey, long value, int userHandle) {
1457        try {
1458            getLockSettings().setLong(secureSettingKey, value, userHandle);
1459        } catch (RemoteException re) {
1460            // What can we do?
1461            Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1462        }
1463    }
1464
1465    private String getString(String secureSettingKey) {
1466        return getString(secureSettingKey, getCurrentOrCallingUserId());
1467    }
1468
1469    private String getString(String secureSettingKey, int userHandle) {
1470        try {
1471            return getLockSettings().getString(secureSettingKey, null, userHandle);
1472        } catch (RemoteException re) {
1473            return null;
1474        }
1475    }
1476
1477    private void setString(String secureSettingKey, String value, int userHandle) {
1478        try {
1479            getLockSettings().setString(secureSettingKey, value, userHandle);
1480        } catch (RemoteException re) {
1481            // What can we do?
1482            Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1483        }
1484    }
1485
1486    public boolean isSecure() {
1487        long mode = getKeyguardStoredPasswordQuality();
1488        final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1489        final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1490                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
1491                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1492                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1493                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
1494        final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
1495                || isPassword && savedPasswordExists();
1496        return secure;
1497    }
1498
1499    /**
1500     * Sets the emergency button visibility based on isEmergencyCallCapable().
1501     *
1502     * If the emergency button is visible, sets the text on the emergency button
1503     * to indicate what action will be taken.
1504     *
1505     * If there's currently a call in progress, the button will take them to the call
1506     * @param button The button to update
1507     * @param shown Indicates whether the given screen wants the emergency button to show at all
1508     * @param showIcon Indicates whether to show a phone icon for the button.
1509     */
1510    public void updateEmergencyCallButtonState(Button button, boolean shown, boolean showIcon) {
1511        if (isEmergencyCallCapable() && shown) {
1512            button.setVisibility(View.VISIBLE);
1513        } else {
1514            button.setVisibility(View.GONE);
1515            return;
1516        }
1517
1518        int textId;
1519        if (isInCall()) {
1520            // show "return to call" text and show phone icon
1521            textId = R.string.lockscreen_return_to_call;
1522            int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
1523            button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
1524        } else {
1525            textId = R.string.lockscreen_emergency_call;
1526            int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
1527            button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
1528        }
1529        button.setText(textId);
1530    }
1531
1532    /**
1533     * Resumes a call in progress. Typically launched from the EmergencyCall button
1534     * on various lockscreens.
1535     */
1536    public void resumeCall() {
1537        getTelecommManager().showInCallScreen(false);
1538    }
1539
1540    /**
1541     * @return {@code true} if there is a call currently in progress, {@code false} otherwise.
1542     */
1543    public boolean isInCall() {
1544        return getTelecommManager().isInCall();
1545    }
1546
1547    private TelecomManager getTelecommManager() {
1548        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
1549    }
1550
1551    private void finishBiometricWeak() {
1552        setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
1553
1554        // Launch intent to show final screen, this also
1555        // moves the temporary gallery to the actual gallery
1556        Intent intent = new Intent();
1557        intent.setClassName("com.android.facelock",
1558                "com.android.facelock.SetupEndScreen");
1559        mContext.startActivity(intent);
1560    }
1561
1562    public void setPowerButtonInstantlyLocks(boolean enabled) {
1563        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
1564    }
1565
1566    public boolean getPowerButtonInstantlyLocks() {
1567        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
1568    }
1569
1570    public static boolean isSafeModeEnabled() {
1571        try {
1572            return IWindowManager.Stub.asInterface(
1573                    ServiceManager.getService("window")).isSafeModeEnabled();
1574        } catch (RemoteException e) {
1575            // Shouldn't happen!
1576        }
1577        return false;
1578    }
1579
1580    /**
1581     * Determine whether the user has selected any non-system widgets in keyguard
1582     *
1583     * @return true if widgets have been selected
1584     */
1585    public boolean hasWidgetsEnabledInKeyguard(int userid) {
1586        int widgets[] = getAppWidgets(userid);
1587        for (int i = 0; i < widgets.length; i++) {
1588            if (widgets[i] > 0) {
1589                return true;
1590            }
1591        }
1592        return false;
1593    }
1594
1595    public boolean getWidgetsEnabled() {
1596        return getWidgetsEnabled(getCurrentOrCallingUserId());
1597    }
1598
1599    public boolean getWidgetsEnabled(int userId) {
1600        return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
1601    }
1602
1603    public void setWidgetsEnabled(boolean enabled) {
1604        setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
1605    }
1606
1607    public void setWidgetsEnabled(boolean enabled, int userId) {
1608        setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
1609    }
1610
1611    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
1612        setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
1613    }
1614
1615    public List<ComponentName> getEnabledTrustAgents() {
1616        return getEnabledTrustAgents(getCurrentOrCallingUserId());
1617    }
1618
1619    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1620        StringBuilder sb = new StringBuilder();
1621        for (ComponentName cn : activeTrustAgents) {
1622            if (sb.length() > 0) {
1623                sb.append(',');
1624            }
1625            sb.append(cn.flattenToShortString());
1626        }
1627        setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
1628        getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
1629    }
1630
1631    public List<ComponentName> getEnabledTrustAgents(int userId) {
1632        String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1633        if (TextUtils.isEmpty(serialized)) {
1634            return null;
1635        }
1636        String[] split = serialized.split(",");
1637        ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1638        for (String s : split) {
1639            if (!TextUtils.isEmpty(s)) {
1640                activeTrustAgents.add(ComponentName.unflattenFromString(s));
1641            }
1642        }
1643        return activeTrustAgents;
1644    }
1645
1646    /**
1647     * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
1648     */
1649    public void requireCredentialEntry(int userId) {
1650        getTrustManager().reportRequireCredentialEntry(userId);
1651    }
1652
1653    private void onAfterChangingPassword() {
1654        getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
1655    }
1656
1657    public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1658        final int value = Settings.Global.getInt(mContentResolver,
1659                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1660        return value == -1 ? defaultValue : (value != 0);
1661    }
1662
1663    public void setCredentialRequiredToDecrypt(boolean required) {
1664        if (getCurrentUser() != UserHandle.USER_OWNER) {
1665            Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
1666            return;
1667        }
1668        Settings.Global.putInt(mContext.getContentResolver(),
1669                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1670    }
1671}
1672