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