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