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