blob: 1096e347afb751bd764fd6bcf771b2a6f1bd628e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Jim Miller78c48f62013-03-01 15:28:33 -080019import android.Manifest;
Amith Yamasani4b4b9542012-09-14 13:36:29 -070020import android.app.ActivityManagerNative;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080021import android.app.admin.DevicePolicyManager;
Adrian Roos82142c22014-03-27 14:56:59 +010022import android.app.trust.TrustManager;
Adrian Roos82142c22014-03-27 14:56:59 +010023import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080025import android.content.Context;
Danielle Millett58396982011-09-30 13:55:07 -040026import android.content.pm.PackageManager;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070027import android.os.AsyncTask;
Jason parksf7b3cd42011-01-27 09:28:25 -060028import android.os.IBinder;
Jim Miller69ac9882010-02-24 15:35:05 -080029import android.os.RemoteException;
30import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.SystemClock;
Jim Miller6848dc82014-10-13 18:51:53 -070032import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070033import android.os.UserHandle;
Jason parksf7b3cd42011-01-27 09:28:25 -060034import android.os.storage.IMountService;
Paul Lawrence8e397362014-01-27 15:22:30 -080035import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.text.TextUtils;
38import android.util.Log;
39
Michael Jurka1254f2f2012-10-25 11:44:31 -070040import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010041
Narayan Kamath78108a32014-12-16 12:56:23 +000042import java.nio.charset.StandardCharsets;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080043import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080045import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010046import java.util.ArrayList;
47import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import java.util.List;
49
Adrian Roosc2e01682015-01-15 23:20:20 +010050import libcore.util.HexEncoding;
51
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070053 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 */
55public class LockPatternUtils {
56
57 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040058 private static final boolean DEBUG = false;
Jim Miller69aa4a92009-12-22 19:03:28 -080059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 /**
61 * The maximum number of incorrect attempts before the user is prevented
62 * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
63 */
64 public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
65
66 /**
67 * The number of incorrect attempts before which we fall back on an alternative
68 * method of verifying the user, and resetting their lock pattern.
69 */
70 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
71
72 /**
73 * How long the user is prevented from trying again after entering the
74 * wrong pattern too many times.
75 */
76 public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
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
Jim Miller4f369952011-08-19 18:29:22 -070083
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 /**
91 * The minimum number of dots in a valid pattern.
92 */
93 public static final int MIN_LOCK_PATTERN_SIZE = 4;
94
95 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +010096 * The minimum size of a valid password.
97 */
98 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
99
100 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 * 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 */
Jim Miller4f369952011-08-19 18:29:22 -0700105 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100107 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800108 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
109 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
110 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800111 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100112 @Deprecated
113 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800114 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
115 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
116 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100117 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700118 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
119 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100120 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400121 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
122 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800123 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
124 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100125 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700126 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800128 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700129
Jim Miller187ec582013-04-15 18:27:54 -0700130 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
131 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
132 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
133
Adrian Roos82142c22014-03-27 14:56:59 +0100134 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
135
Jim Miller85516d02014-01-31 17:08:37 -0800136 // Maximum allowed number of repeated or ordered characters in a sequence before we'll
137 // consider it a complex PIN/password.
138 public static final int MAX_ALLOWED_SEQUENCE = 3;
139
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800140 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800142 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700143 private ILockSettings mLockSettingsService;
Jim Milleree82f8f2012-10-01 16:26:18 -0700144
Jim Miller78c48f62013-03-01 15:28:33 -0800145 private final boolean mMultiUserMode;
146
Jim Milleree82f8f2012-10-01 16:26:18 -0700147 // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
148 private static volatile int sCurrentUserId = UserHandle.USER_NULL;
Dianne Hackbornde4c26f2011-07-17 13:42:47 -0700149
Jim Millercd709882010-03-25 18:24:02 -0700150 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800151 if (mDevicePolicyManager == null) {
152 mDevicePolicyManager =
153 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
154 if (mDevicePolicyManager == null) {
155 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
156 new IllegalStateException("Stack trace:"));
157 }
158 }
159 return mDevicePolicyManager;
160 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700161
Adrian Roos82142c22014-03-27 14:56:59 +0100162 private TrustManager getTrustManager() {
163 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
164 if (trust == null) {
165 Log.e(TAG, "Can't get TrustManagerService: is it running?",
166 new IllegalStateException("Stack trace:"));
167 }
168 return trust;
169 }
170
Jim Miller31f90b62010-01-20 13:35:20 -0800171 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800172 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800173 mContentResolver = context.getContentResolver();
Jim Miller78c48f62013-03-01 15:28:33 -0800174
175 // If this is being called by the system or by an application like keyguard that
176 // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
177 // mode where calls are for the current user rather than the user of the calling process.
178 mMultiUserMode = context.checkCallingOrSelfPermission(
179 Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700180 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800181
Amith Yamasani52c489c2012-03-28 11:42:42 -0700182 private ILockSettings getLockSettings() {
183 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100184 ILockSettings service = ILockSettings.Stub.asInterface(
185 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100186 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700187 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700188 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
190
Jim Miller31f90b62010-01-20 13:35:20 -0800191 public int getRequestedMinimumPasswordLength() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700192 return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800193 }
194
Jim Miller31f90b62010-01-20 13:35:20 -0800195 /**
196 * Gets the device policy password mode. If the mode is non-specific, returns
197 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800198 */
Jim Millercd709882010-03-25 18:24:02 -0700199 public int getRequestedPasswordQuality() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700200 return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800201 }
202
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700203 public int getRequestedPasswordHistoryLength() {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100204 return getRequestedPasswordHistoryLength(getCurrentOrCallingUserId());
205 }
206
207 private int getRequestedPasswordHistoryLength(int userId) {
208 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700209 }
210
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700211 public int getRequestedPasswordMinimumLetters() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700212 return getDevicePolicyManager().getPasswordMinimumLetters(null,
213 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700214 }
215
216 public int getRequestedPasswordMinimumUpperCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700217 return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
218 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700219 }
220
221 public int getRequestedPasswordMinimumLowerCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700222 return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
223 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700224 }
225
226 public int getRequestedPasswordMinimumNumeric() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700227 return getDevicePolicyManager().getPasswordMinimumNumeric(null,
228 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700229 }
230
231 public int getRequestedPasswordMinimumSymbols() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700232 return getDevicePolicyManager().getPasswordMinimumSymbols(null,
233 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700234 }
235
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700236 public int getRequestedPasswordMinimumNonLetter() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700237 return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
238 getCurrentOrCallingUserId());
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700239 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700240
Jim Miller31f90b62010-01-20 13:35:20 -0800241 public void reportFailedPasswordAttempt() {
Adrian Roos4f994eb2014-07-23 15:45:05 +0200242 int userId = getCurrentOrCallingUserId();
243 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
244 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
245 getTrustManager().reportRequireCredentialEntry(userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800246 }
247
248 public void reportSuccessfulPasswordAttempt() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700249 getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
Adrian Roos82142c22014-03-27 14:56:59 +0100250 getTrustManager().reportUnlockAttempt(true /* authenticated */,
251 getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800252 }
253
Amith Yamasani52c489c2012-03-28 11:42:42 -0700254 public void setCurrentUser(int userId) {
Jim Milleree82f8f2012-10-01 16:26:18 -0700255 sCurrentUserId = userId;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700256 }
257
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700258 public int getCurrentUser() {
Jim Milleree82f8f2012-10-01 16:26:18 -0700259 if (sCurrentUserId != UserHandle.USER_NULL) {
Jim Miller25645d82012-09-21 14:47:54 -0700260 // Someone is regularly updating using setCurrentUser() use that value.
Jim Milleree82f8f2012-10-01 16:26:18 -0700261 return sCurrentUserId;
Jim Miller25645d82012-09-21 14:47:54 -0700262 }
263 try {
264 return ActivityManagerNative.getDefault().getCurrentUser().id;
265 } catch (RemoteException re) {
266 return UserHandle.USER_OWNER;
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700267 }
268 }
269
Amith Yamasani52c489c2012-03-28 11:42:42 -0700270 private int getCurrentOrCallingUserId() {
Jim Miller78c48f62013-03-01 15:28:33 -0800271 if (mMultiUserMode) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700272 // TODO: This is a little inefficient. See if all users of this are able to
273 // handle USER_CURRENT and pass that instead.
274 return getCurrentUser();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700275 } else {
Jim Miller78c48f62013-03-01 15:28:33 -0800276 return UserHandle.getCallingUserId();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700277 }
278 }
279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700281 * Check to see if a pattern matches the saved pattern.
282 * If pattern matches, return an opaque attestation that the challenge
283 * was verified.
284 *
285 * @param pattern The pattern to check.
286 * @param challenge The challenge to verify against the pattern
287 * @return the attestation that the challenge was verified, or null.
288 */
289 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge) {
290 final int userId = getCurrentOrCallingUserId();
291 try {
292 return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
293 } catch (RemoteException re) {
294 return null;
295 }
296 }
297
298 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 * Check to see if a pattern matches the saved pattern. If no pattern exists,
300 * always returns true.
301 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800302 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 */
304 public boolean checkPattern(List<LockPatternView.Cell> pattern) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700305 final int userId = getCurrentOrCallingUserId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 try {
Jim Millerde1af082013-09-11 14:58:26 -0700307 return getLockSettings().checkPattern(patternToString(pattern), userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700308 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 return true;
310 }
311 }
312
313 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700314 * Check to see if a password matches the saved password.
315 * If password matches, return an opaque attestation that the challenge
316 * was verified.
317 *
318 * @param password The password to check.
319 * @param challenge The challenge to verify against the password
320 * @return the attestation that the challenge was verified, or null.
321 */
322 public byte[] verifyPassword(String password, long challenge) {
323 final int userId = getCurrentOrCallingUserId();
324 try {
325 return getLockSettings().verifyPassword(password, challenge, userId);
326 } catch (RemoteException re) {
327 return null;
328 }
329 }
330
331 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800332 * Check to see if a password matches the saved password. If no password exists,
333 * always returns true.
334 * @param password The password to check.
335 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800337 public boolean checkPassword(String password) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700338 final int userId = getCurrentOrCallingUserId();
Jim Miller69aa4a92009-12-22 19:03:28 -0800339 try {
Jim Millerde1af082013-09-11 14:58:26 -0700340 return getLockSettings().checkPassword(password, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700341 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800342 return true;
343 }
344 }
345
346 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000347 * Check to see if vold already has the password.
348 * Note that this also clears vold's copy of the password.
349 * @return Whether the vold password matches or not.
350 */
351 public boolean checkVoldPassword() {
352 final int userId = getCurrentOrCallingUserId();
353 try {
354 return getLockSettings().checkVoldPassword(userId);
355 } catch (RemoteException re) {
356 return false;
357 }
358 }
359
360 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700361 * Check to see if a password matches any of the passwords stored in the
362 * password history.
363 *
364 * @param password The password to check.
365 * @return Whether the password matches any in the history.
366 */
367 public boolean checkPasswordHistory(String password) {
Adrian Roosdce01222015-01-07 22:39:01 +0100368 int userId = getCurrentOrCallingUserId();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400369 String passwordHashString = new String(
Adrian Roosdce01222015-01-07 22:39:01 +0100370 passwordToHash(password, userId), StandardCharsets.UTF_8);
371 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700372 if (passwordHistory == null) {
373 return false;
374 }
375 // Password History may be too long...
376 int passwordHashLength = passwordHashString.length();
377 int passwordHistoryLength = getRequestedPasswordHistoryLength();
378 if(passwordHistoryLength == 0) {
379 return false;
380 }
381 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
382 + passwordHistoryLength - 1;
383 if (passwordHistory.length() > neededPasswordHistoryLength) {
384 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
385 }
386 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700387 }
388
389 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800390 * Check to see if the user has stored a lock pattern.
391 * @return Whether a saved pattern exists.
392 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100393 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700394 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100395 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700396 } catch (RemoteException re) {
397 return false;
398 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800399 }
400
401 /**
402 * Check to see if the user has stored a lock pattern.
403 * @return Whether a saved pattern exists.
404 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100405 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700406 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100407 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700408 } catch (RemoteException re) {
409 return false;
410 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800411 }
412
413 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700414 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
415 * currently cleared.
416 *
417 * @return True if the user has ever chosen a pattern.
418 */
419 public boolean isPatternEverChosen() {
Adrian Roosdce01222015-01-07 22:39:01 +0100420 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, getCurrentOrCallingUserId());
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700421 }
422
423 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700424 * Used by device policy manager to validate the current password
425 * information it has.
426 */
427 public int getActivePasswordQuality() {
Adrian Roosdce01222015-01-07 22:39:01 +0100428 return getActivePasswordQuality(getCurrentOrCallingUserId());
429 }
430
431 /**
432 * Used by device policy manager to validate the current password
433 * information it has.
434 */
435 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100436 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100437
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100438 if (isLockPasswordEnabled(quality, userId)) {
439 // Quality is a password and a password exists. Return the quality.
440 return quality;
441 }
442
443 if (isLockPatternEnabled(quality, userId)) {
444 // Quality is a pattern and a pattern exists. Return the quality.
445 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700446 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400447
Adrian Roosdce01222015-01-07 22:39:01 +0100448 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700449 }
Jim Millercd709882010-03-25 18:24:02 -0700450
Adrian Roos230635e2015-01-07 20:50:29 +0100451 public void clearLock() {
452 clearLock(getCurrentOrCallingUserId());
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100453 }
454
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700455 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800456 * Clear any lock pattern or password.
457 */
Adrian Roos230635e2015-01-07 20:50:29 +0100458 public void clearLock(int userHandle) {
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100459 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100460
461 try {
Andres Morales8fa56652015-03-31 09:19:50 -0700462 getLockSettings().setLockPassword(null, null, userHandle);
463 getLockSettings().setLockPattern(null, null, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100464 } catch (RemoteException e) {
465 // well, we tried...
466 }
467
468 if (userHandle == UserHandle.USER_OWNER) {
469 // Set the encryption password to default.
470 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
471 }
472
Wen ZHANG95bbbdd2015-04-15 19:32:06 +0100473 setCredentialRequiredToDecrypt(false);
474
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100475 getDevicePolicyManager().setActivePasswordState(
476 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
477
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100478 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800479 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800480
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800481 /**
Jim Miller2a98a4c2010-11-19 18:49:26 -0800482 * Disable showing lock screen at all when the DevicePolicyManager allows it.
483 * This is only meaningful if pattern, pin or password are not set.
484 *
485 * @param disable Disables lock screen when true
486 */
487 public void setLockScreenDisabled(boolean disable) {
Benjamin Franz51ed7942015-04-07 16:34:56 +0100488 setLockScreenDisabled(disable, getCurrentOrCallingUserId());
Jim Miller2a98a4c2010-11-19 18:49:26 -0800489 }
490
491 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100492 * Disable showing lock screen at all for a given user.
493 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800494 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100495 * @param disable Disables lock screen when true
496 * @param userId User ID of the user this has effect on
497 */
498 public void setLockScreenDisabled(boolean disable, int userId) {
499 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
500 }
501
502 /**
503 * Determine if LockScreen is disabled for the current user. This is used to decide whether
504 * LockScreen is shown after reboot or after screen timeout / short press on power.
505 *
506 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800507 */
508 public boolean isLockScreenDisabled() {
Benjamin Franz51ed7942015-04-07 16:34:56 +0100509 return !isSecure() &&
510 getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId());
Jim Miller2a98a4c2010-11-19 18:49:26 -0800511 }
512
513 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700514 * Save a lock pattern.
515 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700516 * @param savedPattern The previously saved pattern, or null if none
Danielle Millett2364a222011-12-21 17:02:32 -0500517 */
Andres Morales8fa56652015-03-31 09:19:50 -0700518 public void saveLockPattern(List<LockPatternView.Cell> pattern,
519 String savedPattern) {
520 this.saveLockPattern(pattern, savedPattern, getCurrentOrCallingUserId());
Danielle Millett2364a222011-12-21 17:02:32 -0500521 }
522
Andres Morales8fa56652015-03-31 09:19:50 -0700523 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
524 this.saveLockPattern(pattern, null, userId);
525 }
Danielle Millett2364a222011-12-21 17:02:32 -0500526 /**
527 * Save a lock pattern.
528 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700529 * @param savedPattern The previously saved pattern, converted to String format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100530 * @param userId the user whose pattern is to be saved.
531 */
Andres Morales8fa56652015-03-31 09:19:50 -0700532 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 try {
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100534 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
535 throw new IllegalArgumentException("pattern must not be null and at least "
536 + MIN_LOCK_PATTERN_SIZE + " dots long.");
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100537 }
538
Andres Morales8fa56652015-03-31 09:19:50 -0700539 getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800540 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100541
542 // Update the device encryption password.
543 if (userId == UserHandle.USER_OWNER
544 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400545 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100546 clearEncryptionPassword();
547 } else {
548 String stringPattern = patternToString(pattern);
549 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
Paul Lawrence8e397362014-01-27 15:22:30 -0800550 }
Jim Miller31f90b62010-01-20 13:35:20 -0800551 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100552
553 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
554
555 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
556 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
557 pattern.size(), 0, 0, 0, 0, 0, 0, userId);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100558 onAfterChangingPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700559 } catch (RemoteException re) {
560 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 }
562 }
563
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100564 private void updateCryptoUserInfo(int userId) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700565 if (userId != UserHandle.USER_OWNER) {
566 return;
567 }
568
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100569 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700570
571 IBinder service = ServiceManager.getService("mount");
572 if (service == null) {
573 Log.e(TAG, "Could not find the mount service to update the user info");
574 return;
575 }
576
577 IMountService mountService = IMountService.Stub.asInterface(service);
578 try {
579 Log.d(TAG, "Setting owner info");
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700580 mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700581 } catch (RemoteException e) {
582 Log.e(TAG, "Error changing user info", e);
583 }
584 }
585
Jim Miller187ec582013-04-15 18:27:54 -0700586 public void setOwnerInfo(String info, int userId) {
587 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100588 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700589 }
590
591 public void setOwnerInfoEnabled(boolean enabled) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100592 int userId = getCurrentOrCallingUserId();
593 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
594 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700595 }
596
597 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100598 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700599 }
600
601 public boolean isOwnerInfoEnabled() {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100602 return isOwnerInfoEnabled(getCurrentOrCallingUserId());
603 }
604
605 private boolean isOwnerInfoEnabled(int userId) {
606 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700607 }
608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700610 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800611 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700612 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800613 boolean hasDigit = false;
614 boolean hasNonDigit = false;
615 final int len = password.length();
616 for (int i = 0; i < len; i++) {
617 if (Character.isDigit(password.charAt(i))) {
618 hasDigit = true;
619 } else {
620 hasNonDigit = true;
621 }
622 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800623
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700624 if (hasNonDigit && hasDigit) {
625 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800626 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800627 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700628 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800629 }
630 if (hasDigit) {
Jim Miller85516d02014-01-31 17:08:37 -0800631 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
632 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
633 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800634 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700635 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800636 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800637
Jim Miller85516d02014-01-31 17:08:37 -0800638 private static int categoryChar(char c) {
639 if ('a' <= c && c <= 'z') return 0;
640 if ('A' <= c && c <= 'Z') return 1;
641 if ('0' <= c && c <= '9') return 2;
642 return 3;
643 }
644
645 private static int maxDiffCategory(int category) {
646 if (category == 0 || category == 1) return 1;
647 else if (category == 2) return 10;
648 return 0;
649 }
650
651 /*
652 * Returns the maximum length of a sequential characters. A sequence is defined as
653 * monotonically increasing characters with a constant interval or the same character repeated.
654 *
655 * For example:
656 * maxLengthSequence("1234") == 4
657 * maxLengthSequence("1234abc") == 4
658 * maxLengthSequence("aabc") == 3
659 * maxLengthSequence("qwertyuio") == 1
660 * maxLengthSequence("@ABC") == 3
661 * maxLengthSequence(";;;;") == 4 (anything that repeats)
662 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
663 *
664 * @param string the pass
665 * @return the number of sequential letters or digits
666 */
667 public static int maxLengthSequence(String string) {
668 if (string.length() == 0) return 0;
669 char previousChar = string.charAt(0);
670 int category = categoryChar(previousChar); //current category of the sequence
671 int diff = 0; //difference between two consecutive characters
672 boolean hasDiff = false; //if we are currently targeting a sequence
673 int maxLength = 0; //maximum length of a sequence already found
674 int startSequence = 0; //where the current sequence started
675 for (int current = 1; current < string.length(); current++) {
676 char currentChar = string.charAt(current);
677 int categoryCurrent = categoryChar(currentChar);
678 int currentDiff = (int) currentChar - (int) previousChar;
679 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
680 maxLength = Math.max(maxLength, current - startSequence);
681 startSequence = current;
682 hasDiff = false;
683 category = categoryCurrent;
684 }
685 else {
686 if(hasDiff && currentDiff != diff) {
687 maxLength = Math.max(maxLength, current - startSequence);
688 startSequence = current - 1;
689 }
690 diff = currentDiff;
691 hasDiff = true;
692 }
693 previousChar = currentChar;
694 }
695 maxLength = Math.max(maxLength, string.length() - startSequence);
696 return maxLength;
697 }
698
Jason parksf7b3cd42011-01-27 09:28:25 -0600699 /** Update the encryption password if it is enabled **/
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700700 private void updateEncryptionPassword(final int type, final String password) {
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700701 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600702 return;
703 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700704 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600705 if (service == null) {
706 Log.e(TAG, "Could not find the mount service to update the encryption password");
707 return;
708 }
709
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700710 new AsyncTask<Void, Void, Void>() {
711 @Override
712 protected Void doInBackground(Void... dummy) {
713 IMountService mountService = IMountService.Stub.asInterface(service);
714 try {
715 mountService.changeEncryptionPassword(type, password);
716 } catch (RemoteException e) {
717 Log.e(TAG, "Error changing encryption password", e);
718 }
719 return null;
720 }
721 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600722 }
723
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800724 /**
Jim Millercd709882010-03-25 18:24:02 -0700725 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800726 * as the requested mode, but will adjust the mode to be as good as the
727 * pattern.
Jim Miller69aa4a92009-12-22 19:03:28 -0800728 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700729 * @param savedPassword The previously saved lock password, or null if none
Jim Millercd709882010-03-25 18:24:02 -0700730 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Jim Miller69aa4a92009-12-22 19:03:28 -0800731 */
Andres Morales8fa56652015-03-31 09:19:50 -0700732 public void saveLockPassword(String password, String savedPassword, int quality) {
733 saveLockPassword(password, savedPassword, quality, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700734 }
735
736 /**
737 * Save a lock password. Does not ensure that the password is as good
738 * as the requested mode, but will adjust the mode to be as good as the
739 * pattern.
740 * @param password The password to save
741 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700742 * @param userHandle The userId of the user to change the password for
743 */
Andres Morales8fa56652015-03-31 09:19:50 -0700744 public void saveLockPassword(String password, String savedPassword, int quality,
745 int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800746 try {
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800747 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100748 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
749 throw new IllegalArgumentException("password must not be null and at least "
750 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller31f90b62010-01-20 13:35:20 -0800751 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100752
Andres Morales8fa56652015-03-31 09:19:50 -0700753 getLockSettings().setLockPassword(password, savedPassword, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100754 int computedQuality = computePasswordQuality(password);
755
756 // Update the device encryption password.
757 if (userHandle == UserHandle.USER_OWNER
758 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400759 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100760 clearEncryptionPassword();
761 } else {
762 boolean numeric = computedQuality
763 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
764 boolean numericComplex = computedQuality
765 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
766 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
767 : StorageManager.CRYPT_TYPE_PASSWORD;
768 updateEncryptionPassword(type, password);
769 }
770 }
771
772 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
773 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
774 int letters = 0;
775 int uppercase = 0;
776 int lowercase = 0;
777 int numbers = 0;
778 int symbols = 0;
779 int nonletter = 0;
780 for (int i = 0; i < password.length(); i++) {
781 char c = password.charAt(i);
782 if (c >= 'A' && c <= 'Z') {
783 letters++;
784 uppercase++;
785 } else if (c >= 'a' && c <= 'z') {
786 letters++;
787 lowercase++;
788 } else if (c >= '0' && c <= '9') {
789 numbers++;
790 nonletter++;
791 } else {
792 symbols++;
793 nonletter++;
794 }
795 }
796 dpm.setActivePasswordState(Math.max(quality, computedQuality),
797 password.length(), letters, uppercase, lowercase,
798 numbers, symbols, nonletter, userHandle);
799 } else {
800 // The password is not anything.
801 dpm.setActivePasswordState(
802 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
803 0, 0, 0, 0, 0, 0, 0, userHandle);
804 }
805
806 // Add the password to the password history. We assume all
807 // password hashes have the same length for simplicity of implementation.
808 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
809 if (passwordHistory == null) {
810 passwordHistory = "";
811 }
812 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
813 if (passwordHistoryLength == 0) {
814 passwordHistory = "";
815 } else {
816 byte[] hash = passwordToHash(password, userHandle);
817 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
818 // Cut it to contain passwordHistoryLength hashes
819 // and passwordHistoryLength -1 commas.
820 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
821 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
822 .length()));
823 }
824 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100825 onAfterChangingPassword(userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700826 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800827 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700828 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800829 }
830 }
831
Jim Millercd709882010-03-25 18:24:02 -0700832 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700833 * Gets whether the device is encrypted.
834 *
835 * @return Whether the device is encrypted.
836 */
837 public static boolean isDeviceEncrypted() {
838 IMountService mountService = IMountService.Stub.asInterface(
839 ServiceManager.getService("mount"));
840 try {
841 return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
842 && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
843 } catch (RemoteException re) {
844 Log.e(TAG, "Error getting encryption state", re);
845 }
846 return true;
847 }
848
849 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700850 * Determine if the device supports encryption, even if it's set to default. This
851 * differs from isDeviceEncrypted() in that it returns true even if the device is
852 * encrypted with the default password.
853 * @return true if device encryption is enabled
854 */
855 public static boolean isDeviceEncryptionEnabled() {
856 final String status = SystemProperties.get("ro.crypto.state", "unsupported");
857 return "encrypted".equalsIgnoreCase(status);
858 }
859
860 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700861 * Clears the encryption password.
862 */
863 public void clearEncryptionPassword() {
864 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
865 }
866
867 /**
Jim Millercd709882010-03-25 18:24:02 -0700868 * Retrieves the quality mode we're in.
869 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
870 *
871 * @return stored password quality
872 */
873 public int getKeyguardStoredPasswordQuality() {
Adrian Roos1572ee32014-09-01 16:24:32 +0200874 return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId());
875 }
876
877 /**
878 * Retrieves the quality mode for {@param userHandle}.
879 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
880 *
881 * @return stored password quality
882 */
883 public int getKeyguardStoredPasswordQuality(int userHandle) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100884 return (int) getLong(PASSWORD_TYPE_KEY,
Adrian Roos1572ee32014-09-01 16:24:32 +0200885 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700886 }
887
Danielle Millett58396982011-09-30 13:55:07 -0400888 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 * Deserialize a pattern.
890 * @param string The pattern serialized with {@link #patternToString}
891 * @return The pattern.
892 */
893 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100894 if (string == null) {
895 return null;
896 }
897
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 List<LockPatternView.Cell> result = Lists.newArrayList();
899
900 final byte[] bytes = string.getBytes();
901 for (int i = 0; i < bytes.length; i++) {
902 byte b = bytes[i];
903 result.add(LockPatternView.Cell.of(b / 3, b % 3));
904 }
905 return result;
906 }
907
908 /**
909 * Serialize a pattern.
910 * @param pattern The pattern.
911 * @return The pattern in string form.
912 */
913 public static String patternToString(List<LockPatternView.Cell> pattern) {
914 if (pattern == null) {
915 return "";
916 }
917 final int patternSize = pattern.size();
918
919 byte[] res = new byte[patternSize];
920 for (int i = 0; i < patternSize; i++) {
921 LockPatternView.Cell cell = pattern.get(i);
922 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
923 }
924 return new String(res);
925 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 /*
928 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
929 * at least a second level of protection. First level is that the file
930 * is in a location only readable by the system process.
931 * @param pattern the gesture pattern.
932 * @return the hash of the pattern in a byte array.
933 */
Jim Millerde1af082013-09-11 14:58:26 -0700934 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 if (pattern == null) {
936 return null;
937 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 final int patternSize = pattern.size();
940 byte[] res = new byte[patternSize];
941 for (int i = 0; i < patternSize; i++) {
942 LockPatternView.Cell cell = pattern.get(i);
943 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
944 }
945 try {
946 MessageDigest md = MessageDigest.getInstance("SHA-1");
947 byte[] hash = md.digest(res);
948 return hash;
949 } catch (NoSuchAlgorithmException nsa) {
950 return res;
951 }
952 }
953
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400954 private String getSalt(int userId) {
955 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800956 if (salt == 0) {
957 try {
958 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400959 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
960 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800961 } catch (NoSuchAlgorithmException e) {
962 // Throw an exception rather than storing a password we'll never be able to recover
963 throw new IllegalStateException("Couldn't get SecureRandom number", e);
964 }
965 }
966 return Long.toHexString(salt);
967 }
968
Jim Miller69aa4a92009-12-22 19:03:28 -0800969 /*
970 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
971 * Not the most secure, but it is at least a second level of protection. First level is that
972 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +0000973 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800974 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +0000975 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800976 * @return the hash of the pattern in a byte array.
977 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400978 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800979 if (password == null) {
980 return null;
981 }
Narayan Kamath78108a32014-12-16 12:56:23 +0000982
Jim Miller69aa4a92009-12-22 19:03:28 -0800983 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400984 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +0000985 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
986 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -0800987
Narayan Kamath78108a32014-12-16 12:56:23 +0000988 byte[] combined = new byte[sha1.length + md5.length];
989 System.arraycopy(sha1, 0, combined, 0, sha1.length);
990 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
991
992 final char[] hexEncoded = HexEncoding.encode(combined);
993 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
994 } catch (NoSuchAlgorithmException e) {
995 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -0800996 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800997 }
998
999 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001000 * @return Whether the lock screen is secured.
1001 */
1002 public boolean isSecure() {
1003 return isSecure(getCurrentOrCallingUserId());
1004 }
1005
1006 /**
1007 * @param userId the user for which to report the value
1008 * @return Whether the lock screen is secured.
1009 */
1010 public boolean isSecure(int userId) {
1011 int mode = getKeyguardStoredPasswordQuality(userId);
1012 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1013 }
1014
1015 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001016 * @return Whether the lock password is enabled
Jim Miller69aa4a92009-12-22 19:03:28 -08001017 */
1018 public boolean isLockPasswordEnabled() {
Adrian Roosdce01222015-01-07 22:39:01 +01001019 return isLockPasswordEnabled(getCurrentOrCallingUserId());
1020 }
1021
Adrian Roosdce01222015-01-07 22:39:01 +01001022 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001023 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1024 }
1025
1026 private boolean isLockPasswordEnabled(int mode, int userId) {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001027 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1028 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001029 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001030 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1031 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001032 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001033 }
1034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001036 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 */
1038 public boolean isLockPatternEnabled() {
Adrian Roos50bfeec2014-11-20 16:21:11 +01001039 return isLockPatternEnabled(getCurrentOrCallingUserId());
1040 }
1041
Adrian Roos50bfeec2014-11-20 16:21:11 +01001042 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001043 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001044 }
1045
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001046 private boolean isLockPatternEnabled(int mode, int userId) {
1047 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1048 && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 }
1050
1051 /**
1052 * @return Whether the visible pattern is enabled.
1053 */
1054 public boolean isVisiblePatternEnabled() {
Adrian Roosdce01222015-01-07 22:39:01 +01001055 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, getCurrentOrCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 }
1057
1058 /**
1059 * Set whether the visible pattern is enabled.
1060 */
1061 public void setVisiblePatternEnabled(boolean enabled) {
Adrian Roosdce01222015-01-07 22:39:01 +01001062 int userId = getCurrentOrCallingUserId();
1063
1064 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001065
1066 // Update for crypto if owner
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001067 if (userId != UserHandle.USER_OWNER) {
1068 return;
1069 }
1070
1071 IBinder service = ServiceManager.getService("mount");
1072 if (service == null) {
1073 Log.e(TAG, "Could not find the mount service to update the user info");
1074 return;
1075 }
1076
1077 IMountService mountService = IMountService.Stub.asInterface(service);
1078 try {
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001079 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001080 } catch (RemoteException e) {
1081 Log.e(TAG, "Error changing pattern visible state", e);
1082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084
1085 /**
1086 * @return Whether tactile feedback for the pattern is enabled.
1087 */
1088 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001089 return Settings.System.getIntForUser(mContentResolver,
1090 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092
1093 /**
1094 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1095 * pattern until the deadline has passed.
1096 * @return the chosen deadline.
1097 */
1098 public long setLockoutAttemptDeadline() {
1099 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
Adrian Roosdce01222015-01-07 22:39:01 +01001100 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, getCurrentOrCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 return deadline;
1102 }
1103
1104 /**
1105 * @return The elapsed time in millis in the future when the user is allowed to
1106 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1107 * enter a pattern.
1108 */
1109 public long getLockoutAttemptDeadline() {
Adrian Roosdce01222015-01-07 22:39:01 +01001110 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, getCurrentOrCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 final long now = SystemClock.elapsedRealtime();
1112 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
1113 return 0L;
1114 }
1115 return deadline;
1116 }
1117
Jim Millerf45bb402013-08-20 18:58:32 -07001118 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001119 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001120 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001121 } catch (RemoteException re) {
1122 return defaultValue;
1123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 }
1125
Jim Millerf45bb402013-08-20 18:58:32 -07001126 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001127 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001128 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001129 } catch (RemoteException re) {
1130 // What can we do?
1131 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 }
1134
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001135 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1136 try {
1137 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1138 } catch (RemoteException re) {
1139 return defaultValue;
1140 }
1141 }
1142
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001143 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001144 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001145 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001146 } catch (RemoteException re) {
1147 // What can we do?
1148 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 }
1151
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001152 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001153 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001154 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001155 } catch (RemoteException re) {
1156 return null;
1157 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001158 }
1159
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001160 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001161 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001162 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001163 } catch (RemoteException re) {
1164 // What can we do?
1165 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1166 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001167 }
1168
Jim Millera4edd152012-01-06 18:24:04 -08001169 public void setPowerButtonInstantlyLocks(boolean enabled) {
Adrian Roosdce01222015-01-07 22:39:01 +01001170 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, getCurrentOrCallingUserId());
Jim Millera4edd152012-01-06 18:24:04 -08001171 }
1172
1173 public boolean getPowerButtonInstantlyLocks() {
Adrian Roosdce01222015-01-07 22:39:01 +01001174 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true,
1175 getCurrentOrCallingUserId());
Jim Millera4edd152012-01-06 18:24:04 -08001176 }
Jim Millera9768602012-11-06 22:17:25 -08001177
Adrian Roos82142c22014-03-27 14:56:59 +01001178 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
1179 setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
1180 }
1181
1182 public List<ComponentName> getEnabledTrustAgents() {
1183 return getEnabledTrustAgents(getCurrentOrCallingUserId());
1184 }
1185
1186 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1187 StringBuilder sb = new StringBuilder();
1188 for (ComponentName cn : activeTrustAgents) {
1189 if (sb.length() > 0) {
1190 sb.append(',');
1191 }
1192 sb.append(cn.flattenToShortString());
1193 }
1194 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
1195 getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
1196 }
1197
1198 public List<ComponentName> getEnabledTrustAgents(int userId) {
1199 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1200 if (TextUtils.isEmpty(serialized)) {
1201 return null;
1202 }
1203 String[] split = serialized.split(",");
1204 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1205 for (String s : split) {
1206 if (!TextUtils.isEmpty(s)) {
1207 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1208 }
1209 }
1210 return activeTrustAgents;
1211 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001212
1213 /**
1214 * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
1215 */
1216 public void requireCredentialEntry(int userId) {
1217 getTrustManager().reportRequireCredentialEntry(userId);
1218 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001219
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001220 private void onAfterChangingPassword(int userHandle) {
1221 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001222 }
Jim Millerdd5de712014-10-16 19:50:18 -07001223
1224 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1225 final int value = Settings.Global.getInt(mContentResolver,
1226 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1227 return value == -1 ? defaultValue : (value != 0);
1228 }
1229
1230 public void setCredentialRequiredToDecrypt(boolean required) {
1231 if (getCurrentUser() != UserHandle.USER_OWNER) {
1232 Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
1233 return;
1234 }
1235 Settings.Global.putInt(mContext.getContentResolver(),
1236 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1237 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001238
1239 private boolean isDoNotAskCredentialsOnBootSet() {
1240 return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
1241 }
1242
1243 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1244 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1245 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246}