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.annotation.IntDef;
20import android.app.admin.DevicePolicyManager;
21import android.app.trust.IStrongAuthTracker;
22import android.app.trust.TrustManager;
23import android.content.ComponentName;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.pm.UserInfo;
27import android.os.AsyncTask;
28import android.os.Handler;
29import android.os.IBinder;
30import android.os.Looper;
31import android.os.Message;
32import android.os.RemoteException;
33import android.os.ServiceManager;
34import android.os.SystemClock;
35import android.os.SystemProperties;
36import android.os.UserHandle;
37import android.os.UserManager;
38import android.os.storage.IMountService;
39import android.os.storage.StorageManager;
40import android.provider.Settings;
41import android.text.TextUtils;
42import android.util.Log;
43import android.util.SparseIntArray;
44
45import com.google.android.collect.Lists;
46
47import java.lang.annotation.Retention;
48import java.lang.annotation.RetentionPolicy;
49import java.nio.charset.StandardCharsets;
50import java.security.MessageDigest;
51import java.security.NoSuchAlgorithmException;
52import java.security.SecureRandom;
53import java.util.ArrayList;
54import java.util.Collection;
55import java.util.List;
56
57import libcore.util.HexEncoding;
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 key to identify when the lock pattern enabled flag is being acccessed for legacy reasons.
69     */
70    public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
71
72    /**
73     * The number of incorrect attempts before which we fall back on an alternative
74     * method of verifying the user, and resetting their lock pattern.
75     */
76    public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
77
78    /**
79     * The interval of the countdown for showing progress of the lockout.
80     */
81    public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
82
83
84    /**
85     * This dictates when we start telling the user that continued failed attempts will wipe
86     * their device.
87     */
88    public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
89
90    /**
91     * The minimum number of dots in a valid pattern.
92     */
93    public static final int MIN_LOCK_PATTERN_SIZE = 4;
94
95    /**
96     * The minimum size of a valid password.
97     */
98    public static final int MIN_LOCK_PASSWORD_SIZE = 4;
99
100    /**
101     * The minimum number of dots the user must include in a wrong pattern
102     * attempt for it to be counted against the counts that affect
103     * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
104     */
105    public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
106
107    @Deprecated
108    public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
109    public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
110    public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
111    public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
112    public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
113    @Deprecated
114    public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
115    public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
116    public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
117    public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
118    @Deprecated
119    public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
120            = "lockscreen.biometric_weak_fallback";
121    @Deprecated
122    public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
123            = "lockscreen.biometricweakeverchosen";
124    public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
125            = "lockscreen.power_button_instantly_locks";
126    @Deprecated
127    public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
128
129    public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
130
131    private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
132    private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
133            Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
134
135    private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
136
137    private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
138    private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
139
140    // Maximum allowed number of repeated or ordered characters in a sequence before we'll
141    // consider it a complex PIN/password.
142    public static final int MAX_ALLOWED_SEQUENCE = 3;
143
144    public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
145    public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
146
147    private final Context mContext;
148    private final ContentResolver mContentResolver;
149    private DevicePolicyManager mDevicePolicyManager;
150    private ILockSettings mLockSettingsService;
151    private UserManager mUserManager;
152
153    /**
154     * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
155     *
156     * This returns the lazily-peristed value and should only be used by TrustManagerService.
157     */
158    public boolean isTrustUsuallyManaged(int userId) {
159        if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
160            throw new IllegalStateException("May only be called by TrustManagerService. "
161                    + "Use TrustManager.isTrustUsuallyManaged()");
162        }
163        try {
164            return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
165        } catch (RemoteException e) {
166            return false;
167        }
168    }
169
170    public void setTrustUsuallyManaged(boolean managed, int userId) {
171        try {
172            getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
173        } catch (RemoteException e) {
174            // System dead.
175        }
176    }
177
178    public void userPresent(int userId) {
179        try {
180            getLockSettings().userPresent(userId);
181        } catch (RemoteException e) {
182            throw e.rethrowFromSystemServer();
183        }
184    }
185
186    public static final class RequestThrottledException extends Exception {
187        private int mTimeoutMs;
188        public RequestThrottledException(int timeoutMs) {
189            mTimeoutMs = timeoutMs;
190        }
191
192        /**
193         * @return The amount of time in ms before another request may
194         * be executed
195         */
196        public int getTimeoutMs() {
197            return mTimeoutMs;
198        }
199
200    }
201
202    public DevicePolicyManager getDevicePolicyManager() {
203        if (mDevicePolicyManager == null) {
204            mDevicePolicyManager =
205                (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
206            if (mDevicePolicyManager == null) {
207                Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
208                        new IllegalStateException("Stack trace:"));
209            }
210        }
211        return mDevicePolicyManager;
212    }
213
214    private UserManager getUserManager() {
215        if (mUserManager == null) {
216            mUserManager = UserManager.get(mContext);
217        }
218        return mUserManager;
219    }
220
221    private TrustManager getTrustManager() {
222        TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
223        if (trust == null) {
224            Log.e(TAG, "Can't get TrustManagerService: is it running?",
225                    new IllegalStateException("Stack trace:"));
226        }
227        return trust;
228    }
229
230    public LockPatternUtils(Context context) {
231        mContext = context;
232        mContentResolver = context.getContentResolver();
233    }
234
235    private ILockSettings getLockSettings() {
236        if (mLockSettingsService == null) {
237            ILockSettings service = ILockSettings.Stub.asInterface(
238                    ServiceManager.getService("lock_settings"));
239            mLockSettingsService = service;
240        }
241        return mLockSettingsService;
242    }
243
244    public int getRequestedMinimumPasswordLength(int userId) {
245        return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
246    }
247
248    /**
249     * Gets the device policy password mode. If the mode is non-specific, returns
250     * MODE_PATTERN which allows the user to choose anything.
251     */
252    public int getRequestedPasswordQuality(int userId) {
253        return getDevicePolicyManager().getPasswordQuality(null, userId);
254    }
255
256    private int getRequestedPasswordHistoryLength(int userId) {
257        return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
258    }
259
260    public int getRequestedPasswordMinimumLetters(int userId) {
261        return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
262    }
263
264    public int getRequestedPasswordMinimumUpperCase(int userId) {
265        return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
266    }
267
268    public int getRequestedPasswordMinimumLowerCase(int userId) {
269        return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
270    }
271
272    public int getRequestedPasswordMinimumNumeric(int userId) {
273        return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
274    }
275
276    public int getRequestedPasswordMinimumSymbols(int userId) {
277        return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
278    }
279
280    public int getRequestedPasswordMinimumNonLetter(int userId) {
281        return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
282    }
283
284    public void reportFailedPasswordAttempt(int userId) {
285        getDevicePolicyManager().reportFailedPasswordAttempt(userId);
286        getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
287        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
288    }
289
290    public void reportSuccessfulPasswordAttempt(int userId) {
291        getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
292        getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
293    }
294
295    public int getCurrentFailedPasswordAttempts(int userId) {
296        return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
297    }
298
299    public int getMaximumFailedPasswordsForWipe(int userId) {
300        return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
301                null /* componentName */, userId);
302    }
303
304    /**
305     * Check to see if a pattern matches the saved pattern.
306     * If pattern matches, return an opaque attestation that the challenge
307     * was verified.
308     *
309     * @param pattern The pattern to check.
310     * @param challenge The challenge to verify against the pattern
311     * @return the attestation that the challenge was verified, or null.
312     */
313    public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
314            throws RequestThrottledException {
315        throwIfCalledOnMainThread();
316        try {
317            VerifyCredentialResponse response =
318                getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
319            if (response == null) {
320                // Shouldn't happen
321                return null;
322            }
323
324            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
325                return response.getPayload();
326            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
327                throw new RequestThrottledException(response.getTimeout());
328            } else {
329                return null;
330            }
331        } catch (RemoteException re) {
332            return null;
333        }
334    }
335
336    /**
337     * Check to see if a pattern matches the saved pattern.  If no pattern exists,
338     * always returns true.
339     * @param pattern The pattern to check.
340     * @return Whether the pattern matches the stored one.
341     */
342    public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
343            throws RequestThrottledException {
344        throwIfCalledOnMainThread();
345        try {
346            VerifyCredentialResponse response =
347                    getLockSettings().checkPattern(patternToString(pattern), userId);
348
349            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
350                return true;
351            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
352                throw new RequestThrottledException(response.getTimeout());
353            } else {
354                return false;
355            }
356        } catch (RemoteException re) {
357            return true;
358        }
359    }
360
361    /**
362     * Check to see if a password matches the saved password.
363     * If password matches, return an opaque attestation that the challenge
364     * was verified.
365     *
366     * @param password The password to check.
367     * @param challenge The challenge to verify against the password
368     * @return the attestation that the challenge was verified, or null.
369     */
370    public byte[] verifyPassword(String password, long challenge, int userId)
371            throws RequestThrottledException {
372        throwIfCalledOnMainThread();
373        try {
374            VerifyCredentialResponse response =
375                    getLockSettings().verifyPassword(password, challenge, userId);
376
377            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
378                return response.getPayload();
379            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
380                throw new RequestThrottledException(response.getTimeout());
381            } else {
382                return null;
383            }
384        } catch (RemoteException re) {
385            return null;
386        }
387    }
388
389
390    /**
391     * Check to see if a password matches the saved password.
392     * If password matches, return an opaque attestation that the challenge
393     * was verified.
394     *
395     * @param password The password to check.
396     * @param challenge The challenge to verify against the password
397     * @return the attestation that the challenge was verified, or null.
398     */
399    public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
400            int userId) throws RequestThrottledException {
401        throwIfCalledOnMainThread();
402        try {
403            VerifyCredentialResponse response =
404                    getLockSettings().verifyTiedProfileChallenge(password, isPattern, challenge,
405                            userId);
406
407            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
408                return response.getPayload();
409            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
410                throw new RequestThrottledException(response.getTimeout());
411            } else {
412                return null;
413            }
414        } catch (RemoteException re) {
415            return null;
416        }
417    }
418
419    /**
420     * Check to see if a password matches the saved password.  If no password exists,
421     * always returns true.
422     * @param password The password to check.
423     * @return Whether the password matches the stored one.
424     */
425    public boolean checkPassword(String password, int userId) throws RequestThrottledException {
426        throwIfCalledOnMainThread();
427        try {
428            VerifyCredentialResponse response =
429                    getLockSettings().checkPassword(password, userId);
430            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
431                return true;
432            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
433                throw new RequestThrottledException(response.getTimeout());
434            } else {
435                return false;
436            }
437        } catch (RemoteException re) {
438            return true;
439        }
440    }
441
442    /**
443     * Check to see if vold already has the password.
444     * Note that this also clears vold's copy of the password.
445     * @return Whether the vold password matches or not.
446     */
447    public boolean checkVoldPassword(int userId) {
448        try {
449            return getLockSettings().checkVoldPassword(userId);
450        } catch (RemoteException re) {
451            return false;
452        }
453    }
454
455    /**
456     * Check to see if a password matches any of the passwords stored in the
457     * password history.
458     *
459     * @param password The password to check.
460     * @return Whether the password matches any in the history.
461     */
462    public boolean checkPasswordHistory(String password, int userId) {
463        String passwordHashString = new String(
464                passwordToHash(password, userId), StandardCharsets.UTF_8);
465        String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
466        if (passwordHistory == null) {
467            return false;
468        }
469        // Password History may be too long...
470        int passwordHashLength = passwordHashString.length();
471        int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
472        if(passwordHistoryLength == 0) {
473            return false;
474        }
475        int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
476                + passwordHistoryLength - 1;
477        if (passwordHistory.length() > neededPasswordHistoryLength) {
478            passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
479        }
480        return passwordHistory.contains(passwordHashString);
481    }
482
483    /**
484     * Check to see if the user has stored a lock pattern.
485     * @return Whether a saved pattern exists.
486     */
487    private boolean savedPatternExists(int userId) {
488        try {
489            return getLockSettings().havePattern(userId);
490        } catch (RemoteException re) {
491            return false;
492        }
493    }
494
495    /**
496     * Check to see if the user has stored a lock pattern.
497     * @return Whether a saved pattern exists.
498     */
499    private boolean savedPasswordExists(int userId) {
500        try {
501            return getLockSettings().havePassword(userId);
502        } catch (RemoteException re) {
503            return false;
504        }
505    }
506
507    /**
508     * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
509     * currently cleared.
510     *
511     * @return True if the user has ever chosen a pattern.
512     */
513    public boolean isPatternEverChosen(int userId) {
514        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
515    }
516
517    /**
518     * Used by device policy manager to validate the current password
519     * information it has.
520     */
521    public int getActivePasswordQuality(int userId) {
522        int quality = getKeyguardStoredPasswordQuality(userId);
523
524        if (isLockPasswordEnabled(quality, userId)) {
525            // Quality is a password and a password exists. Return the quality.
526            return quality;
527        }
528
529        if (isLockPatternEnabled(quality, userId)) {
530            // Quality is a pattern and a pattern exists. Return the quality.
531            return quality;
532        }
533
534        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
535    }
536
537    /**
538     * Use it to reset keystore without wiping work profile
539     */
540    public void resetKeyStore(int userId) {
541        try {
542            getLockSettings().resetKeyStore(userId);
543        } catch (RemoteException e) {
544            // It should not happen
545            Log.e(TAG, "Couldn't reset keystore " + e);
546        }
547    }
548
549    /**
550     * Clear any lock pattern or password.
551     */
552    public void clearLock(int userHandle) {
553        setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
554
555        try {
556            getLockSettings().setLockPassword(null, null, userHandle);
557            getLockSettings().setLockPattern(null, null, userHandle);
558        } catch (RemoteException e) {
559            // well, we tried...
560        }
561
562        if (userHandle == UserHandle.USER_SYSTEM) {
563            // Set the encryption password to default.
564            updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
565            setCredentialRequiredToDecrypt(false);
566        }
567
568        getDevicePolicyManager().setActivePasswordState(
569                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
570
571        onAfterChangingPassword(userHandle);
572    }
573
574    /**
575     * Disable showing lock screen at all for a given user.
576     * This is only meaningful if pattern, pin or password are not set.
577     *
578     * @param disable Disables lock screen when true
579     * @param userId User ID of the user this has effect on
580     */
581    public void setLockScreenDisabled(boolean disable, int userId) {
582        setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
583    }
584
585    /**
586     * Determine if LockScreen is disabled for the current user. This is used to decide whether
587     * LockScreen is shown after reboot or after screen timeout / short press on power.
588     *
589     * @return true if lock screen is disabled
590     */
591    public boolean isLockScreenDisabled(int userId) {
592        return !isSecure(userId) &&
593                getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId);
594    }
595
596    /**
597     * Save a lock pattern.
598     * @param pattern The new pattern to save.
599     * @param userId the user whose pattern is to be saved.
600     */
601    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
602        this.saveLockPattern(pattern, null, userId);
603    }
604    /**
605     * Save a lock pattern.
606     * @param pattern The new pattern to save.
607     * @param savedPattern The previously saved pattern, converted to String format
608     * @param userId the user whose pattern is to be saved.
609     */
610    public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
611        try {
612            if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
613                throw new IllegalArgumentException("pattern must not be null and at least "
614                        + MIN_LOCK_PATTERN_SIZE + " dots long.");
615            }
616
617            getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
618            DevicePolicyManager dpm = getDevicePolicyManager();
619
620            // Update the device encryption password.
621            if (userId == UserHandle.USER_SYSTEM
622                    && LockPatternUtils.isDeviceEncryptionEnabled()) {
623                if (!shouldEncryptWithCredentials(true)) {
624                    clearEncryptionPassword();
625                } else {
626                    String stringPattern = patternToString(pattern);
627                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
628                }
629            }
630
631            setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
632
633            setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
634            dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
635                    pattern.size(), 0, 0, 0, 0, 0, 0, userId);
636            onAfterChangingPassword(userId);
637        } catch (RemoteException re) {
638            Log.e(TAG, "Couldn't save lock pattern " + re);
639        }
640    }
641
642    private void updateCryptoUserInfo(int userId) {
643        if (userId != UserHandle.USER_SYSTEM) {
644            return;
645        }
646
647        final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
648
649        IBinder service = ServiceManager.getService("mount");
650        if (service == null) {
651            Log.e(TAG, "Could not find the mount service to update the user info");
652            return;
653        }
654
655        IMountService mountService = IMountService.Stub.asInterface(service);
656        try {
657            Log.d(TAG, "Setting owner info");
658            mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
659        } catch (RemoteException e) {
660            Log.e(TAG, "Error changing user info", e);
661        }
662    }
663
664    public void setOwnerInfo(String info, int userId) {
665        setString(LOCK_SCREEN_OWNER_INFO, info, userId);
666        updateCryptoUserInfo(userId);
667    }
668
669    public void setOwnerInfoEnabled(boolean enabled, int userId) {
670        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
671        updateCryptoUserInfo(userId);
672    }
673
674    public String getOwnerInfo(int userId) {
675        return getString(LOCK_SCREEN_OWNER_INFO, userId);
676    }
677
678    public boolean isOwnerInfoEnabled(int userId) {
679        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
680    }
681
682    /**
683     * Sets the device owner information. If the information is {@code null} or empty then the
684     * device owner info is cleared.
685     *
686     * @param info Device owner information which will be displayed instead of the user
687     * owner info.
688     */
689    public void setDeviceOwnerInfo(String info) {
690        if (info != null && info.isEmpty()) {
691            info = null;
692        }
693
694        setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
695    }
696
697    public String getDeviceOwnerInfo() {
698        return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
699    }
700
701    public boolean isDeviceOwnerInfoEnabled() {
702        return getDeviceOwnerInfo() != null;
703    }
704
705    /**
706     * Compute the password quality from the given password string.
707     */
708    static public int computePasswordQuality(String password) {
709        boolean hasDigit = false;
710        boolean hasNonDigit = false;
711        final int len = password.length();
712        for (int i = 0; i < len; i++) {
713            if (Character.isDigit(password.charAt(i))) {
714                hasDigit = true;
715            } else {
716                hasNonDigit = true;
717            }
718        }
719
720        if (hasNonDigit && hasDigit) {
721            return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
722        }
723        if (hasNonDigit) {
724            return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
725        }
726        if (hasDigit) {
727            return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
728                    ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
729                    : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
730        }
731        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
732    }
733
734    private static int categoryChar(char c) {
735        if ('a' <= c && c <= 'z') return 0;
736        if ('A' <= c && c <= 'Z') return 1;
737        if ('0' <= c && c <= '9') return 2;
738        return 3;
739    }
740
741    private static int maxDiffCategory(int category) {
742        if (category == 0 || category == 1) return 1;
743        else if (category == 2) return 10;
744        return 0;
745    }
746
747    /*
748     * Returns the maximum length of a sequential characters.  A sequence is defined as
749     * monotonically increasing characters with a constant interval or the same character repeated.
750     *
751     * For example:
752     * maxLengthSequence("1234") == 4
753     * maxLengthSequence("1234abc") == 4
754     * maxLengthSequence("aabc") == 3
755     * maxLengthSequence("qwertyuio") == 1
756     * maxLengthSequence("@ABC") == 3
757     * maxLengthSequence(";;;;") == 4 (anything that repeats)
758     * maxLengthSequence(":;<=>") == 1  (ordered, but not composed of alphas or digits)
759     *
760     * @param string the pass
761     * @return the number of sequential letters or digits
762     */
763    public static int maxLengthSequence(String string) {
764        if (string.length() == 0) return 0;
765        char previousChar = string.charAt(0);
766        int category = categoryChar(previousChar); //current category of the sequence
767        int diff = 0; //difference between two consecutive characters
768        boolean hasDiff = false; //if we are currently targeting a sequence
769        int maxLength = 0; //maximum length of a sequence already found
770        int startSequence = 0; //where the current sequence started
771        for (int current = 1; current < string.length(); current++) {
772            char currentChar = string.charAt(current);
773            int categoryCurrent = categoryChar(currentChar);
774            int currentDiff = (int) currentChar - (int) previousChar;
775            if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
776                maxLength = Math.max(maxLength, current - startSequence);
777                startSequence = current;
778                hasDiff = false;
779                category = categoryCurrent;
780            }
781            else {
782                if(hasDiff && currentDiff != diff) {
783                    maxLength = Math.max(maxLength, current - startSequence);
784                    startSequence = current - 1;
785                }
786                diff = currentDiff;
787                hasDiff = true;
788            }
789            previousChar = currentChar;
790        }
791        maxLength = Math.max(maxLength, string.length() - startSequence);
792        return maxLength;
793    }
794
795    /** Update the encryption password if it is enabled **/
796    private void updateEncryptionPassword(final int type, final String password) {
797        if (!isDeviceEncryptionEnabled()) {
798            return;
799        }
800        final IBinder service = ServiceManager.getService("mount");
801        if (service == null) {
802            Log.e(TAG, "Could not find the mount service to update the encryption password");
803            return;
804        }
805
806        new AsyncTask<Void, Void, Void>() {
807            @Override
808            protected Void doInBackground(Void... dummy) {
809                IMountService mountService = IMountService.Stub.asInterface(service);
810                try {
811                    mountService.changeEncryptionPassword(type, password);
812                } catch (RemoteException e) {
813                    Log.e(TAG, "Error changing encryption password", e);
814                }
815                return null;
816            }
817        }.execute();
818    }
819
820    /**
821     * Save a lock password.  Does not ensure that the password is as good
822     * as the requested mode, but will adjust the mode to be as good as the
823     * password.
824     * @param password The password to save
825     * @param savedPassword The previously saved lock password, or null if none
826     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
827     * @param userHandle The userId of the user to change the password for
828     */
829    public void saveLockPassword(String password, String savedPassword, int quality,
830            int userHandle) {
831        try {
832            DevicePolicyManager dpm = getDevicePolicyManager();
833            if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
834                throw new IllegalArgumentException("password must not be null and at least "
835                        + "of length " + MIN_LOCK_PASSWORD_SIZE);
836            }
837
838            getLockSettings().setLockPassword(password, savedPassword, userHandle);
839            getLockSettings().setSeparateProfileChallengeEnabled(userHandle, true, null);
840            int computedQuality = computePasswordQuality(password);
841
842            // Update the device encryption password.
843            if (userHandle == UserHandle.USER_SYSTEM
844                    && LockPatternUtils.isDeviceEncryptionEnabled()) {
845                if (!shouldEncryptWithCredentials(true)) {
846                    clearEncryptionPassword();
847                } else {
848                    boolean numeric = computedQuality
849                            == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
850                    boolean numericComplex = computedQuality
851                            == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
852                    int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
853                            : StorageManager.CRYPT_TYPE_PASSWORD;
854                    updateEncryptionPassword(type, password);
855                }
856            }
857
858            setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
859            if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
860                int letters = 0;
861                int uppercase = 0;
862                int lowercase = 0;
863                int numbers = 0;
864                int symbols = 0;
865                int nonletter = 0;
866                for (int i = 0; i < password.length(); i++) {
867                    char c = password.charAt(i);
868                    if (c >= 'A' && c <= 'Z') {
869                        letters++;
870                        uppercase++;
871                    } else if (c >= 'a' && c <= 'z') {
872                        letters++;
873                        lowercase++;
874                    } else if (c >= '0' && c <= '9') {
875                        numbers++;
876                        nonletter++;
877                    } else {
878                        symbols++;
879                        nonletter++;
880                    }
881                }
882                dpm.setActivePasswordState(Math.max(quality, computedQuality),
883                        password.length(), letters, uppercase, lowercase,
884                        numbers, symbols, nonletter, userHandle);
885            } else {
886                // The password is not anything.
887                dpm.setActivePasswordState(
888                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
889                        0, 0, 0, 0, 0, 0, 0, userHandle);
890            }
891
892            // Add the password to the password history. We assume all
893            // password hashes have the same length for simplicity of implementation.
894            String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
895            if (passwordHistory == null) {
896                passwordHistory = "";
897            }
898            int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
899            if (passwordHistoryLength == 0) {
900                passwordHistory = "";
901            } else {
902                byte[] hash = passwordToHash(password, userHandle);
903                passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
904                // Cut it to contain passwordHistoryLength hashes
905                // and passwordHistoryLength -1 commas.
906                passwordHistory = passwordHistory.substring(0, Math.min(hash.length
907                        * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
908                        .length()));
909            }
910            setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
911            onAfterChangingPassword(userHandle);
912        } catch (RemoteException re) {
913            // Cant do much
914            Log.e(TAG, "Unable to save lock password " + re);
915        }
916    }
917
918    /**
919     * Determine if the device supports encryption, even if it's set to default. This
920     * differs from isDeviceEncrypted() in that it returns true even if the device is
921     * encrypted with the default password.
922     * @return true if device encryption is enabled
923     */
924    public static boolean isDeviceEncryptionEnabled() {
925        return StorageManager.isEncrypted();
926    }
927
928    /**
929     * Determine if the device is file encrypted
930     * @return true if device is file encrypted
931     */
932    public static boolean isFileEncryptionEnabled() {
933        return StorageManager.isFileEncryptedNativeOrEmulated();
934    }
935
936    /**
937     * Clears the encryption password.
938     */
939    public void clearEncryptionPassword() {
940        updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
941    }
942
943    /**
944     * Retrieves the quality mode for {@param userHandle}.
945     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
946     *
947     * @return stored password quality
948     */
949    public int getKeyguardStoredPasswordQuality(int userHandle) {
950        return (int) getLong(PASSWORD_TYPE_KEY,
951                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
952    }
953
954    /**
955     * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
956     * for user handles that do not belong to a managed profile.
957     *
958     * @param userHandle Managed profile user id
959     * @param enabled True if separate challenge is enabled
960     * @param managedUserPassword Managed profile previous password. Null when {@param enabled} is
961     *            true
962     */
963    public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
964            String managedUserPassword) {
965        UserInfo info = getUserManager().getUserInfo(userHandle);
966        if (info.isManagedProfile()) {
967            try {
968                getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
969                        managedUserPassword);
970                onAfterChangingPassword(userHandle);
971            } catch (RemoteException e) {
972                Log.e(TAG, "Couldn't update work profile challenge enabled");
973            }
974        }
975    }
976
977    /**
978     * Retrieves whether the Separate Profile Challenge is enabled for this {@param userHandle}.
979     */
980    public boolean isSeparateProfileChallengeEnabled(int userHandle) {
981        UserInfo info = getUserManager().getUserInfo(userHandle);
982        if (info == null || !info.isManagedProfile()) {
983            return false;
984        }
985        try {
986            return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
987        } catch (RemoteException e) {
988            Log.e(TAG, "Couldn't get separate profile challenge enabled");
989            // Default value is false
990            return false;
991        }
992    }
993
994    /**
995     * Retrieves whether the current DPM allows use of the Profile Challenge.
996     */
997    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
998        UserInfo info = getUserManager().getUserInfo(userHandle);
999        if (info == null || !info.isManagedProfile()) {
1000            return false;
1001        }
1002        return getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
1003    }
1004
1005    /**
1006     * Retrieves whether the current profile and device locks can be unified.
1007     */
1008    public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
1009        return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle);
1010    }
1011
1012    /**
1013     * Deserialize a pattern.
1014     * @param string The pattern serialized with {@link #patternToString}
1015     * @return The pattern.
1016     */
1017    public static List<LockPatternView.Cell> stringToPattern(String string) {
1018        if (string == null) {
1019            return null;
1020        }
1021
1022        List<LockPatternView.Cell> result = Lists.newArrayList();
1023
1024        final byte[] bytes = string.getBytes();
1025        for (int i = 0; i < bytes.length; i++) {
1026            byte b = (byte) (bytes[i] - '1');
1027            result.add(LockPatternView.Cell.of(b / 3, b % 3));
1028        }
1029        return result;
1030    }
1031
1032    /**
1033     * Serialize a pattern.
1034     * @param pattern The pattern.
1035     * @return The pattern in string form.
1036     */
1037    public static String patternToString(List<LockPatternView.Cell> pattern) {
1038        if (pattern == null) {
1039            return "";
1040        }
1041        final int patternSize = pattern.size();
1042
1043        byte[] res = new byte[patternSize];
1044        for (int i = 0; i < patternSize; i++) {
1045            LockPatternView.Cell cell = pattern.get(i);
1046            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
1047        }
1048        return new String(res);
1049    }
1050
1051    public static String patternStringToBaseZero(String pattern) {
1052        if (pattern == null) {
1053            return "";
1054        }
1055        final int patternSize = pattern.length();
1056
1057        byte[] res = new byte[patternSize];
1058        final byte[] bytes = pattern.getBytes();
1059        for (int i = 0; i < patternSize; i++) {
1060            res[i] = (byte) (bytes[i] - '1');
1061        }
1062        return new String(res);
1063    }
1064
1065    /*
1066     * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1067     * at least a second level of protection. First level is that the file
1068     * is in a location only readable by the system process.
1069     * @param pattern the gesture pattern.
1070     * @return the hash of the pattern in a byte array.
1071     */
1072    public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
1073        if (pattern == null) {
1074            return null;
1075        }
1076
1077        final int patternSize = pattern.size();
1078        byte[] res = new byte[patternSize];
1079        for (int i = 0; i < patternSize; i++) {
1080            LockPatternView.Cell cell = pattern.get(i);
1081            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1082        }
1083        try {
1084            MessageDigest md = MessageDigest.getInstance("SHA-1");
1085            byte[] hash = md.digest(res);
1086            return hash;
1087        } catch (NoSuchAlgorithmException nsa) {
1088            return res;
1089        }
1090    }
1091
1092    private String getSalt(int userId) {
1093        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
1094        if (salt == 0) {
1095            try {
1096                salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
1097                setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1098                Log.v(TAG, "Initialized lock password salt for user: " + userId);
1099            } catch (NoSuchAlgorithmException e) {
1100                // Throw an exception rather than storing a password we'll never be able to recover
1101                throw new IllegalStateException("Couldn't get SecureRandom number", e);
1102            }
1103        }
1104        return Long.toHexString(salt);
1105    }
1106
1107    /*
1108     * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1109     * Not the most secure, but it is at least a second level of protection. First level is that
1110     * the file is in a location only readable by the system process.
1111     *
1112     * @param password the gesture pattern.
1113     *
1114     * @return the hash of the pattern in a byte array.
1115     */
1116    public byte[] passwordToHash(String password, int userId) {
1117        if (password == null) {
1118            return null;
1119        }
1120
1121        try {
1122            byte[] saltedPassword = (password + getSalt(userId)).getBytes();
1123            byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1124            byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
1125
1126            byte[] combined = new byte[sha1.length + md5.length];
1127            System.arraycopy(sha1, 0, combined, 0, sha1.length);
1128            System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1129
1130            final char[] hexEncoded = HexEncoding.encode(combined);
1131            return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
1132        } catch (NoSuchAlgorithmException e) {
1133            throw new AssertionError("Missing digest algorithm: ", e);
1134        }
1135    }
1136
1137    /**
1138     * @param userId the user for which to report the value
1139     * @return Whether the lock screen is secured.
1140     */
1141    public boolean isSecure(int userId) {
1142        int mode = getKeyguardStoredPasswordQuality(userId);
1143        return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1144    }
1145
1146    public boolean isLockPasswordEnabled(int userId) {
1147        return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1148    }
1149
1150    private boolean isLockPasswordEnabled(int mode, int userId) {
1151        final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1152                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1153                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
1154                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1155                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
1156                || mode == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
1157        return passwordEnabled && savedPasswordExists(userId);
1158    }
1159
1160    /**
1161     * @return Whether the lock pattern is enabled
1162     */
1163    public boolean isLockPatternEnabled(int userId) {
1164        return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1165    }
1166
1167    @Deprecated
1168    public boolean isLegacyLockPatternEnabled(int userId) {
1169        // Note: this value should default to {@code true} to avoid any reset that might result.
1170        // We must use a special key to read this value, since it will by default return the value
1171        // based on the new logic.
1172        return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1173    }
1174
1175    @Deprecated
1176    public void setLegacyLockPatternEnabled(int userId) {
1177        setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1178    }
1179
1180    private boolean isLockPatternEnabled(int mode, int userId) {
1181        return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1182                && savedPatternExists(userId);
1183    }
1184
1185    /**
1186     * @return Whether the visible pattern is enabled.
1187     */
1188    public boolean isVisiblePatternEnabled(int userId) {
1189        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
1190    }
1191
1192    /**
1193     * Set whether the visible pattern is enabled.
1194     */
1195    public void setVisiblePatternEnabled(boolean enabled, int userId) {
1196        setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
1197
1198        // Update for crypto if owner
1199        if (userId != UserHandle.USER_SYSTEM) {
1200            return;
1201        }
1202
1203        IBinder service = ServiceManager.getService("mount");
1204        if (service == null) {
1205            Log.e(TAG, "Could not find the mount service to update the user info");
1206            return;
1207        }
1208
1209        IMountService mountService = IMountService.Stub.asInterface(service);
1210        try {
1211            mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
1212        } catch (RemoteException e) {
1213            Log.e(TAG, "Error changing pattern visible state", e);
1214        }
1215    }
1216
1217    /**
1218     * Set whether the visible password is enabled for cryptkeeper screen.
1219     */
1220    public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1221        // Update for crypto if owner
1222        if (userId != UserHandle.USER_SYSTEM) {
1223            return;
1224        }
1225
1226        IBinder service = ServiceManager.getService("mount");
1227        if (service == null) {
1228            Log.e(TAG, "Could not find the mount service to update the user info");
1229            return;
1230        }
1231
1232        IMountService mountService = IMountService.Stub.asInterface(service);
1233        try {
1234            mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1235        } catch (RemoteException e) {
1236            Log.e(TAG, "Error changing password visible state", e);
1237        }
1238    }
1239
1240    /**
1241     * @return Whether tactile feedback for the pattern is enabled.
1242     */
1243    public boolean isTactileFeedbackEnabled() {
1244        return Settings.System.getIntForUser(mContentResolver,
1245                Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
1246    }
1247
1248    /**
1249     * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1250     * pattern until the deadline has passed.
1251     * @return the chosen deadline.
1252     */
1253    public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1254        final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
1255        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
1256        setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
1257        return deadline;
1258    }
1259
1260    /**
1261     * @return The elapsed time in millis in the future when the user is allowed to
1262     *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
1263     *   enter a pattern.
1264     */
1265    public long getLockoutAttemptDeadline(int userId) {
1266        long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
1267        final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
1268        final long now = SystemClock.elapsedRealtime();
1269        if (deadline < now && deadline != 0) {
1270            // timeout expired
1271            setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
1272            setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
1273            return 0L;
1274        }
1275
1276        if (deadline > (now + timeoutMs)) {
1277            // device was rebooted, set new deadline
1278            deadline = now + timeoutMs;
1279            setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
1280        }
1281
1282        return deadline;
1283    }
1284
1285    private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
1286        try {
1287            return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
1288        } catch (RemoteException re) {
1289            return defaultValue;
1290        }
1291    }
1292
1293    private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
1294        try {
1295            getLockSettings().setBoolean(secureSettingKey, enabled, userId);
1296        } catch (RemoteException re) {
1297            // What can we do?
1298            Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1299        }
1300    }
1301
1302    private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1303        try {
1304            return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1305        } catch (RemoteException re) {
1306            return defaultValue;
1307        }
1308    }
1309
1310    private void setLong(String secureSettingKey, long value, int userHandle) {
1311        try {
1312            getLockSettings().setLong(secureSettingKey, value, userHandle);
1313        } catch (RemoteException re) {
1314            // What can we do?
1315            Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1316        }
1317    }
1318
1319    private String getString(String secureSettingKey, int userHandle) {
1320        try {
1321            return getLockSettings().getString(secureSettingKey, null, userHandle);
1322        } catch (RemoteException re) {
1323            return null;
1324        }
1325    }
1326
1327    private void setString(String secureSettingKey, String value, int userHandle) {
1328        try {
1329            getLockSettings().setString(secureSettingKey, value, userHandle);
1330        } catch (RemoteException re) {
1331            // What can we do?
1332            Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1333        }
1334    }
1335
1336    public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1337        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
1338    }
1339
1340    public boolean getPowerButtonInstantlyLocks(int userId) {
1341        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
1342    }
1343
1344    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1345        StringBuilder sb = new StringBuilder();
1346        for (ComponentName cn : activeTrustAgents) {
1347            if (sb.length() > 0) {
1348                sb.append(',');
1349            }
1350            sb.append(cn.flattenToShortString());
1351        }
1352        setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
1353        getTrustManager().reportEnabledTrustAgentsChanged(userId);
1354    }
1355
1356    public List<ComponentName> getEnabledTrustAgents(int userId) {
1357        String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1358        if (TextUtils.isEmpty(serialized)) {
1359            return null;
1360        }
1361        String[] split = serialized.split(",");
1362        ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1363        for (String s : split) {
1364            if (!TextUtils.isEmpty(s)) {
1365                activeTrustAgents.add(ComponentName.unflattenFromString(s));
1366            }
1367        }
1368        return activeTrustAgents;
1369    }
1370
1371    /**
1372     * Disable trust until credentials have been entered for user {@param userId}.
1373     *
1374     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1375     *
1376     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1377     */
1378    public void requireCredentialEntry(int userId) {
1379        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
1380    }
1381
1382    /**
1383     * Requests strong authentication for user {@param userId}.
1384     *
1385     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1386     *
1387     * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1388     *                         the reason for and the strength of the requested authentication.
1389     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1390     */
1391    public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1392            int userId) {
1393        try {
1394            getLockSettings().requireStrongAuth(strongAuthReason, userId);
1395        } catch (RemoteException e) {
1396            Log.e(TAG, "Error while requesting strong auth: " + e);
1397        }
1398    }
1399
1400    private void onAfterChangingPassword(int userHandle) {
1401        getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
1402    }
1403
1404    public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1405        final int value = Settings.Global.getInt(mContentResolver,
1406                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1407        return value == -1 ? defaultValue : (value != 0);
1408    }
1409
1410    public void setCredentialRequiredToDecrypt(boolean required) {
1411        if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1412            throw new IllegalStateException(
1413                    "Only the system or primary user may call setCredentialRequiredForDecrypt()");
1414        }
1415
1416        if (isDeviceEncryptionEnabled()){
1417            Settings.Global.putInt(mContext.getContentResolver(),
1418               Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1419        }
1420    }
1421
1422    private boolean isDoNotAskCredentialsOnBootSet() {
1423        return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
1424    }
1425
1426    private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1427        return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1428    }
1429
1430    private void throwIfCalledOnMainThread() {
1431        if (Looper.getMainLooper().isCurrentThread()) {
1432            throw new IllegalStateException("should not be called from the main thread.");
1433        }
1434    }
1435
1436    public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1437        try {
1438            getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1439        } catch (RemoteException e) {
1440            throw new RuntimeException("Could not register StrongAuthTracker");
1441        }
1442    }
1443
1444    public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1445        try {
1446            getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1447        } catch (RemoteException e) {
1448            Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1449        }
1450    }
1451
1452    /**
1453     * @see StrongAuthTracker#getStrongAuthForUser
1454     */
1455    public int getStrongAuthForUser(int userId) {
1456        try {
1457            return getLockSettings().getStrongAuthForUser(userId);
1458        } catch (RemoteException e) {
1459            Log.e(TAG, "Could not get StrongAuth", e);
1460            return StrongAuthTracker.getDefaultFlags(mContext);
1461        }
1462    }
1463
1464    /**
1465     * @see StrongAuthTracker#isTrustAllowedForUser
1466     */
1467    public boolean isTrustAllowedForUser(int userId) {
1468        return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
1469    }
1470
1471    /**
1472     * @see StrongAuthTracker#isFingerprintAllowedForUser
1473     */
1474    public boolean isFingerprintAllowedForUser(int userId) {
1475        return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
1476    }
1477
1478    /**
1479     * Tracks the global strong authentication state.
1480     */
1481    public static class StrongAuthTracker {
1482
1483        @IntDef(flag = true,
1484                value = { STRONG_AUTH_NOT_REQUIRED,
1485                        STRONG_AUTH_REQUIRED_AFTER_BOOT,
1486                        STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
1487                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
1488        @Retention(RetentionPolicy.SOURCE)
1489        public @interface StrongAuthFlags {}
1490
1491        /**
1492         * Strong authentication is not required.
1493         */
1494        public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1495
1496        /**
1497         * Strong authentication is required because the user has not authenticated since boot.
1498         */
1499        public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1500
1501        /**
1502         * Strong authentication is required because a device admin has requested it.
1503         */
1504        public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1505
1506        /**
1507         * Some authentication is required because the user has temporarily disabled trust.
1508         */
1509        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
1510
1511        /**
1512         * Strong authentication is required because the user has been locked out after too many
1513         * attempts.
1514         */
1515        public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1516
1517        /**
1518         * Some authentication is required because the user has entered a wrong credential.
1519         */
1520        public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
1521
1522        private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
1523                | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
1524                | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
1525
1526        private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
1527        private final H mHandler;
1528        private final int mDefaultStrongAuthFlags;
1529
1530        public StrongAuthTracker(Context context) {
1531            this(context, Looper.myLooper());
1532        }
1533
1534        /**
1535         * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1536         *               will be scheduled.
1537         * @param context the current {@link Context}
1538         */
1539        public StrongAuthTracker(Context context, Looper looper) {
1540            mHandler = new H(looper);
1541            mDefaultStrongAuthFlags = getDefaultFlags(context);
1542        }
1543
1544        public static @StrongAuthFlags int getDefaultFlags(Context context) {
1545            boolean strongAuthRequired = context.getResources().getBoolean(
1546                    com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1547            return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
1548        }
1549
1550        /**
1551         * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1552         * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1553         * authentication is required.
1554         *
1555         * @param userId the user for whom the state is queried.
1556         */
1557        public @StrongAuthFlags int getStrongAuthForUser(int userId) {
1558            return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
1559        }
1560
1561        /**
1562         * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1563         * strong authentication requirements.
1564         */
1565        public boolean isTrustAllowedForUser(int userId) {
1566            return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1567        }
1568
1569        /**
1570         * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1571         * current strong authentication requirements.
1572         */
1573        public boolean isFingerprintAllowedForUser(int userId) {
1574            return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
1575        }
1576
1577        /**
1578         * Called when the strong authentication requirements for {@param userId} changed.
1579         */
1580        public void onStrongAuthRequiredChanged(int userId) {
1581        }
1582
1583        protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1584                int userId) {
1585            int oldValue = getStrongAuthForUser(userId);
1586            if (strongAuthFlags != oldValue) {
1587                if (strongAuthFlags == mDefaultStrongAuthFlags) {
1588                    mStrongAuthRequiredForUser.delete(userId);
1589                } else {
1590                    mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1591                }
1592                onStrongAuthRequiredChanged(userId);
1593            }
1594        }
1595
1596
1597        protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1598            @Override
1599            public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1600                    int userId) {
1601                mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1602                        strongAuthFlags, userId).sendToTarget();
1603            }
1604        };
1605
1606        private class H extends Handler {
1607            static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1608
1609            public H(Looper looper) {
1610                super(looper);
1611            }
1612
1613            @Override
1614            public void handleMessage(Message msg) {
1615                switch (msg.what) {
1616                    case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1617                        handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1618                        break;
1619                }
1620            }
1621        };
1622    }
1623}
1624