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