blob: acc3c1c39de1a14653a97b43b5b0f63bd2ff03e0 [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
Jason parksf7b3cd42011-01-27 09:28:25 -060019import com.android.internal.R;
20import com.android.internal.telephony.ITelephony;
21import com.google.android.collect.Lists;
22
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080023import android.app.admin.DevicePolicyManager;
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;
Steven Ross329979c2011-09-28 11:42:56 -040026import android.content.Intent;
Danielle Millett58396982011-09-30 13:55:07 -040027import android.content.pm.PackageManager;
Brad Fitzpatrick90881002010-08-23 18:30:08 -070028import android.os.FileObserver;
Jason parksf7b3cd42011-01-27 09:28:25 -060029import android.os.IBinder;
Jim Miller69ac9882010-02-24 15:35:05 -080030import android.os.RemoteException;
31import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.SystemClock;
Jason parksf7b3cd42011-01-27 09:28:25 -060033import android.os.storage.IMountService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.provider.Settings;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070035import android.security.KeyStore;
Jim Miller69ac9882010-02-24 15:35:05 -080036import android.telephony.TelephonyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.text.TextUtils;
38import android.util.Log;
John Wang0f7b3f82011-05-31 11:20:55 -070039import android.view.View;
Jim Miller69ac9882010-02-24 15:35:05 -080040import android.widget.Button;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Brad Fitzpatrick90881002010-08-23 18:30:08 -070042import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import java.io.FileNotFoundException;
44import java.io.IOException;
45import java.io.RandomAccessFile;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080046import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080048import java.security.SecureRandom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.util.Arrays;
50import java.util.List;
Brad Fitzpatrick90881002010-08-23 18:30:08 -070051import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
53/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070054 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 */
56public class LockPatternUtils {
57
Jim Millercb3521e2011-10-03 20:42:26 -070058 private static final String OPTION_ENABLE_FACELOCK = "enable_facelock";
59
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 private static final String TAG = "LockPatternUtils";
Jim Miller69aa4a92009-12-22 19:03:28 -080061
Brad Fitzpatrick90881002010-08-23 18:30:08 -070062 private static final String SYSTEM_DIRECTORY = "/system/";
63 private static final String LOCK_PATTERN_FILE = "gesture.key";
64 private static final String LOCK_PASSWORD_FILE = "password.key";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66 /**
67 * The maximum number of incorrect attempts before the user is prevented
68 * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
69 */
70 public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
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 * How long the user is prevented from trying again after entering the
80 * wrong pattern too many times.
81 */
82 public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
83
84 /**
85 * The interval of the countdown for showing progress of the lockout.
86 */
87 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
88
Jim Miller4f369952011-08-19 18:29:22 -070089
90 /**
91 * This dictates when we start telling the user that continued failed attempts will wipe
92 * their device.
93 */
94 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
95
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 /**
97 * The minimum number of dots in a valid pattern.
98 */
99 public static final int MIN_LOCK_PATTERN_SIZE = 4;
100
101 /**
102 * The minimum number of dots the user must include in a wrong pattern
103 * attempt for it to be counted against the counts that affect
104 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
105 */
Jim Miller4f369952011-08-19 18:29:22 -0700106 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107
108 private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
109 private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
Jim Miller69aa4a92009-12-22 19:03:28 -0800110 private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
111 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Jim Miller6edf2632011-09-05 16:03:14 -0700112 public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jim Miller11b019d2010-01-20 16:34:45 -0800113 private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
Jim Miller2a98a4c2010-11-19 18:49:26 -0800114 private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
Jim Millercb3521e2011-10-03 20:42:26 -0700115 private final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Jim Miller6edf2632011-09-05 16:03:14 -0700116 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
117 = "lockscreen.biometric_weak_fallback";
Danielle Millett7a072192011-10-03 17:36:01 -0400118 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
119 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800120 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
121 = "lockscreen.power_button_instantly_locks";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700123 private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
124
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800125 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800127 private DevicePolicyManager mDevicePolicyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 private static String sLockPatternFilename;
Jim Miller69aa4a92009-12-22 19:03:28 -0800129 private static String sLockPasswordFilename;
130
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700131 private static final AtomicBoolean sHaveNonZeroPatternFile = new AtomicBoolean(false);
132 private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false);
Jim Miller4f369952011-08-19 18:29:22 -0700133
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700134 private static FileObserver sPasswordObserver;
135
Dianne Hackbornde4c26f2011-07-17 13:42:47 -0700136 private static class PasswordFileObserver extends FileObserver {
137 public PasswordFileObserver(String path, int mask) {
138 super(path, mask);
139 }
140
141 @Override
142 public void onEvent(int event, String path) {
143 if (LOCK_PATTERN_FILE.equals(path)) {
144 Log.d(TAG, "lock pattern file changed");
145 sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
146 } else if (LOCK_PASSWORD_FILE.equals(path)) {
147 Log.d(TAG, "lock password file changed");
148 sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
149 }
150 }
151 }
152
Jim Millercd709882010-03-25 18:24:02 -0700153 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800154 if (mDevicePolicyManager == null) {
155 mDevicePolicyManager =
156 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
157 if (mDevicePolicyManager == null) {
158 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
159 new IllegalStateException("Stack trace:"));
160 }
161 }
162 return mDevicePolicyManager;
163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /**
165 * @param contentResolver Used to look up and save settings.
166 */
Jim Miller31f90b62010-01-20 13:35:20 -0800167 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800168 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800169 mContentResolver = context.getContentResolver();
Jim Miller69aa4a92009-12-22 19:03:28 -0800170
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700171 // Initialize the location of gesture & PIN lock files
172 if (sLockPatternFilename == null) {
173 String dataSystemDirectory =
174 android.os.Environment.getDataDirectory().getAbsolutePath() +
175 SYSTEM_DIRECTORY;
176 sLockPatternFilename = dataSystemDirectory + LOCK_PATTERN_FILE;
177 sLockPasswordFilename = dataSystemDirectory + LOCK_PASSWORD_FILE;
178 sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
179 sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
180 int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
181 FileObserver.MOVED_TO | FileObserver.CREATE;
Dianne Hackbornde4c26f2011-07-17 13:42:47 -0700182 sPasswordObserver = new PasswordFileObserver(dataSystemDirectory, fileObserverMask);
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700183 sPasswordObserver.startWatching();
184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 }
186
Jim Miller31f90b62010-01-20 13:35:20 -0800187 public int getRequestedMinimumPasswordLength() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800188 return getDevicePolicyManager().getPasswordMinimumLength(null);
Jim Miller31f90b62010-01-20 13:35:20 -0800189 }
190
Jim Millercd709882010-03-25 18:24:02 -0700191
Jim Miller31f90b62010-01-20 13:35:20 -0800192 /**
193 * Gets the device policy password mode. If the mode is non-specific, returns
194 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800195 */
Jim Millercd709882010-03-25 18:24:02 -0700196 public int getRequestedPasswordQuality() {
197 return getDevicePolicyManager().getPasswordQuality(null);
Jim Miller31f90b62010-01-20 13:35:20 -0800198 }
199
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700200 public int getRequestedPasswordHistoryLength() {
201 return getDevicePolicyManager().getPasswordHistoryLength(null);
202 }
203
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700204 public int getRequestedPasswordMinimumLetters() {
205 return getDevicePolicyManager().getPasswordMinimumLetters(null);
206 }
207
208 public int getRequestedPasswordMinimumUpperCase() {
209 return getDevicePolicyManager().getPasswordMinimumUpperCase(null);
210 }
211
212 public int getRequestedPasswordMinimumLowerCase() {
213 return getDevicePolicyManager().getPasswordMinimumLowerCase(null);
214 }
215
216 public int getRequestedPasswordMinimumNumeric() {
217 return getDevicePolicyManager().getPasswordMinimumNumeric(null);
218 }
219
220 public int getRequestedPasswordMinimumSymbols() {
221 return getDevicePolicyManager().getPasswordMinimumSymbols(null);
222 }
223
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700224 public int getRequestedPasswordMinimumNonLetter() {
225 return getDevicePolicyManager().getPasswordMinimumNonLetter(null);
226 }
Jim Miller31f90b62010-01-20 13:35:20 -0800227 /**
228 * Returns the actual password mode, as set by keyguard after updating the password.
229 *
230 * @return
231 */
Jim Miller31f90b62010-01-20 13:35:20 -0800232 public void reportFailedPasswordAttempt() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800233 getDevicePolicyManager().reportFailedPasswordAttempt();
Jim Miller31f90b62010-01-20 13:35:20 -0800234 }
235
236 public void reportSuccessfulPasswordAttempt() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800237 getDevicePolicyManager().reportSuccessfulPasswordAttempt();
Jim Miller31f90b62010-01-20 13:35:20 -0800238 }
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 /**
241 * Check to see if a pattern matches the saved pattern. If no pattern exists,
242 * always returns true.
243 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800244 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 */
246 public boolean checkPattern(List<LockPatternView.Cell> pattern) {
247 try {
248 // Read all the bytes from the file
249 RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "r");
250 final byte[] stored = new byte[(int) raf.length()];
251 int got = raf.read(stored, 0, stored.length);
252 raf.close();
253 if (got <= 0) {
254 return true;
255 }
256 // Compare the hash from the file with the entered pattern's hash
257 return Arrays.equals(stored, LockPatternUtils.patternToHash(pattern));
258 } catch (FileNotFoundException fnfe) {
259 return true;
260 } catch (IOException ioe) {
261 return true;
262 }
263 }
264
265 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800266 * Check to see if a password matches the saved password. If no password exists,
267 * always returns true.
268 * @param password The password to check.
269 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800271 public boolean checkPassword(String password) {
272 try {
273 // Read all the bytes from the file
274 RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "r");
275 final byte[] stored = new byte[(int) raf.length()];
276 int got = raf.read(stored, 0, stored.length);
277 raf.close();
278 if (got <= 0) {
279 return true;
280 }
281 // Compare the hash from the file with the entered password's hash
Jim Miller11b019d2010-01-20 16:34:45 -0800282 return Arrays.equals(stored, passwordToHash(password));
Jim Miller69aa4a92009-12-22 19:03:28 -0800283 } catch (FileNotFoundException fnfe) {
284 return true;
285 } catch (IOException ioe) {
286 return true;
287 }
288 }
289
290 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700291 * Check to see if a password matches any of the passwords stored in the
292 * password history.
293 *
294 * @param password The password to check.
295 * @return Whether the password matches any in the history.
296 */
297 public boolean checkPasswordHistory(String password) {
298 String passwordHashString = new String(passwordToHash(password));
299 String passwordHistory = getString(PASSWORD_HISTORY_KEY);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700300 if (passwordHistory == null) {
301 return false;
302 }
303 // Password History may be too long...
304 int passwordHashLength = passwordHashString.length();
305 int passwordHistoryLength = getRequestedPasswordHistoryLength();
306 if(passwordHistoryLength == 0) {
307 return false;
308 }
309 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
310 + passwordHistoryLength - 1;
311 if (passwordHistory.length() > neededPasswordHistoryLength) {
312 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
313 }
314 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700315 }
316
317 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800318 * Check to see if the user has stored a lock pattern.
319 * @return Whether a saved pattern exists.
320 */
321 public boolean savedPatternExists() {
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700322 return sHaveNonZeroPatternFile.get();
Jim Miller69aa4a92009-12-22 19:03:28 -0800323 }
324
325 /**
326 * Check to see if the user has stored a lock pattern.
327 * @return Whether a saved pattern exists.
328 */
329 public boolean savedPasswordExists() {
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700330 return sHaveNonZeroPasswordFile.get();
Jim Miller69aa4a92009-12-22 19:03:28 -0800331 }
332
333 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700334 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
335 * currently cleared.
336 *
337 * @return True if the user has ever chosen a pattern.
338 */
339 public boolean isPatternEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800340 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700341 }
342
343 /**
Danielle Millett7a072192011-10-03 17:36:01 -0400344 * Return true if the user has ever chosen biometric weak. This is true even if biometric
345 * weak is not current set.
346 *
347 * @return True if the user has ever chosen biometric weak.
348 */
349 public boolean isBiometricWeakEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800350 return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
Danielle Millett7a072192011-10-03 17:36:01 -0400351 }
352
353 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700354 * Used by device policy manager to validate the current password
355 * information it has.
356 */
357 public int getActivePasswordQuality() {
Jim Millercd709882010-03-25 18:24:02 -0700358 int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400359 // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
360 // return biometric_weak if that is being used instead of the backup
361 int quality =
362 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
363 switch (quality) {
Jim Millercd709882010-03-25 18:24:02 -0700364 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700365 if (isLockPatternEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700366 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700367 }
Jim Millercd709882010-03-25 18:24:02 -0700368 break;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400369 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
370 if (isBiometricWeakInstalled()) {
371 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
372 }
373 break;
Jim Millercd709882010-03-25 18:24:02 -0700374 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700375 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700376 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700377 }
Jim Millercd709882010-03-25 18:24:02 -0700378 break;
379 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700380 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700381 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700382 }
Jim Millercd709882010-03-25 18:24:02 -0700383 break;
384 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
385 if (isLockPasswordEnabled()) {
386 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
387 }
388 break;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700389 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
390 if (isLockPasswordEnabled()) {
391 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
392 }
393 break;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700394 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400395
Jim Millercd709882010-03-25 18:24:02 -0700396 return activePasswordQuality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700397 }
Jim Millercd709882010-03-25 18:24:02 -0700398
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700399 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800400 * Clear any lock pattern or password.
401 */
Steven Ross329979c2011-09-28 11:42:56 -0400402 public void clearLock(boolean isFallback) {
403 if(!isFallback) deleteGallery();
Jim Millercd709882010-03-25 18:24:02 -0700404 saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800405 setLockPatternEnabled(false);
406 saveLockPattern(null);
Jim Miller93708af12012-01-25 18:26:12 -0800407 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700408 setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800409 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800410
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800411 /**
Jim Miller2a98a4c2010-11-19 18:49:26 -0800412 * Disable showing lock screen at all when the DevicePolicyManager allows it.
413 * This is only meaningful if pattern, pin or password are not set.
414 *
415 * @param disable Disables lock screen when true
416 */
417 public void setLockScreenDisabled(boolean disable) {
418 setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
419 }
420
421 /**
422 * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
423 * show LockScreen or go straight to the home screen.
424 *
425 * @return true if lock screen is can be disabled
426 */
427 public boolean isLockScreenDisabled() {
428 return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
429 }
430
431 /**
Steven Ross3553c292011-09-30 15:48:40 -0400432 * Calls back SetupFaceLock to delete the temporary gallery file
Steven Ross329979c2011-09-28 11:42:56 -0400433 */
434 public void deleteTempGallery() {
Steven Ross3553c292011-09-30 15:48:40 -0400435 Intent intent = new Intent().setClassName("com.android.facelock",
436 "com.android.facelock.SetupFaceLock");
437 intent.putExtra("deleteTempGallery", true);
438 mContext.startActivity(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400439 }
440
441 /**
442 * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
443 */
444 void deleteGallery() {
Danielle Millett58396982011-09-30 13:55:07 -0400445 if(usingBiometricWeak()) {
Steven Ross329979c2011-09-28 11:42:56 -0400446 Intent intent = new Intent().setClassName("com.android.facelock",
447 "com.android.facelock.SetupFaceLock");
448 intent.putExtra("deleteGallery", true);
449 mContext.startActivity(intent);
450 }
451 }
452
453 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700454 * Save a lock pattern.
455 * @param pattern The new pattern to save.
Danielle Millett2364a222011-12-21 17:02:32 -0500456 */
457 public void saveLockPattern(List<LockPatternView.Cell> pattern) {
458 this.saveLockPattern(pattern, false);
459 }
460
461 /**
462 * Save a lock pattern.
463 * @param pattern The new pattern to save.
Jim Miller6edf2632011-09-05 16:03:14 -0700464 * @param isFallback Specifies if this is a fallback to biometric weak
465 */
466 public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 // Compute the hash
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700468 final byte[] hash = LockPatternUtils.patternToHash(pattern);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 try {
470 // Write the hash to file
471 RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "rw");
472 // Truncate the file if pattern is null, to clear the lock
473 if (pattern == null) {
474 raf.setLength(0);
475 } else {
476 raf.write(hash, 0, hash.length);
477 }
478 raf.close();
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800479 DevicePolicyManager dpm = getDevicePolicyManager();
Brian Carlstrome2afc242011-06-02 16:21:55 -0700480 KeyStore keyStore = KeyStore.getInstance();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800481 if (pattern != null) {
Brian Carlstrome2afc242011-06-02 16:21:55 -0700482 keyStore.password(patternToString(pattern));
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800483 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
Jim Miller6edf2632011-09-05 16:03:14 -0700484 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400485 deleteGallery();
Jim Miller6edf2632011-09-05 16:03:14 -0700486 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett2364a222011-12-21 17:02:32 -0500487 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
488 pattern.size(), 0, 0, 0, 0, 0, 0);
Jim Miller6edf2632011-09-05 16:03:14 -0700489 } else {
490 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
491 setLong(PASSWORD_TYPE_ALTERNATE_KEY,
492 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett044a0a72011-11-07 15:42:12 -0500493 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500494 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
495 0, 0, 0, 0, 0, 0, 0);
Jim Miller6edf2632011-09-05 16:03:14 -0700496 }
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800497 } else {
Brian Carlstrome2afc242011-06-02 16:21:55 -0700498 if (keyStore.isEmpty()) {
499 keyStore.reset();
500 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700501 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700502 0, 0, 0, 0, 0);
Jim Miller31f90b62010-01-20 13:35:20 -0800503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 } catch (FileNotFoundException fnfe) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700505 // Cant do much, unless we want to fail over to using the settings
506 // provider
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
508 } catch (IOException ioe) {
509 // Cant do much
510 Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
511 }
512 }
513
514 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700515 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800516 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700517 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800518 boolean hasDigit = false;
519 boolean hasNonDigit = false;
520 final int len = password.length();
521 for (int i = 0; i < len; i++) {
522 if (Character.isDigit(password.charAt(i))) {
523 hasDigit = true;
524 } else {
525 hasNonDigit = true;
526 }
527 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800528
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700529 if (hasNonDigit && hasDigit) {
530 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800531 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800532 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700533 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800534 }
535 if (hasDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700536 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800537 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700538 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800539 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800540
Jason parksf7b3cd42011-01-27 09:28:25 -0600541 /** Update the encryption password if it is enabled **/
542 private void updateEncryptionPassword(String password) {
543 DevicePolicyManager dpm = getDevicePolicyManager();
544 if (dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
545 return;
546 }
547
548 IBinder service = ServiceManager.getService("mount");
549 if (service == null) {
550 Log.e(TAG, "Could not find the mount service to update the encryption password");
551 return;
552 }
553
554 IMountService mountService = IMountService.Stub.asInterface(service);
555 try {
556 mountService.changeEncryptionPassword(password);
557 } catch (RemoteException e) {
558 Log.e(TAG, "Error changing encryption password", e);
559 }
560 }
561
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800562 /**
Jim Millercd709882010-03-25 18:24:02 -0700563 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800564 * as the requested mode, but will adjust the mode to be as good as the
565 * pattern.
Jim Miller69aa4a92009-12-22 19:03:28 -0800566 * @param password The password to save
Jim Millercd709882010-03-25 18:24:02 -0700567 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Jim Miller69aa4a92009-12-22 19:03:28 -0800568 */
Jim Millercd709882010-03-25 18:24:02 -0700569 public void saveLockPassword(String password, int quality) {
Jim Miller6edf2632011-09-05 16:03:14 -0700570 this.saveLockPassword(password, quality, false);
571 }
572
573 /**
574 * Save a lock password. Does not ensure that the password is as good
575 * as the requested mode, but will adjust the mode to be as good as the
576 * pattern.
577 * @param password The password to save
578 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
579 * @param isFallback Specifies if this is a fallback to biometric weak
580 */
581 public void saveLockPassword(String password, int quality, boolean isFallback) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800582 // Compute the hash
Jim Miller11b019d2010-01-20 16:34:45 -0800583 final byte[] hash = passwordToHash(password);
Jim Miller69aa4a92009-12-22 19:03:28 -0800584 try {
585 // Write the hash to file
586 RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "rw");
587 // Truncate the file if pattern is null, to clear the lock
588 if (password == null) {
589 raf.setLength(0);
590 } else {
591 raf.write(hash, 0, hash.length);
592 }
593 raf.close();
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800594 DevicePolicyManager dpm = getDevicePolicyManager();
Brian Carlstrome2afc242011-06-02 16:21:55 -0700595 KeyStore keyStore = KeyStore.getInstance();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800596 if (password != null) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600597 // Update the encryption password.
598 updateEncryptionPassword(password);
599
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700600 // Update the keystore password
Brian Carlstrome2afc242011-06-02 16:21:55 -0700601 keyStore.password(password);
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700602
Jim Millercd709882010-03-25 18:24:02 -0700603 int computedQuality = computePasswordQuality(password);
Jim Miller6edf2632011-09-05 16:03:14 -0700604 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400605 deleteGallery();
Jim Miller6edf2632011-09-05 16:03:14 -0700606 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
Danielle Millett2364a222011-12-21 17:02:32 -0500607 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
608 int letters = 0;
609 int uppercase = 0;
610 int lowercase = 0;
611 int numbers = 0;
612 int symbols = 0;
613 int nonletter = 0;
614 for (int i = 0; i < password.length(); i++) {
615 char c = password.charAt(i);
616 if (c >= 'A' && c <= 'Z') {
617 letters++;
618 uppercase++;
619 } else if (c >= 'a' && c <= 'z') {
620 letters++;
621 lowercase++;
622 } else if (c >= '0' && c <= '9') {
623 numbers++;
624 nonletter++;
625 } else {
626 symbols++;
627 nonletter++;
628 }
629 }
630 dpm.setActivePasswordState(Math.max(quality, computedQuality),
631 password.length(), letters, uppercase, lowercase,
632 numbers, symbols, nonletter);
633 } else {
634 // The password is not anything.
635 dpm.setActivePasswordState(
636 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
637 0, 0, 0, 0, 0, 0, 0);
638 }
Jim Miller6edf2632011-09-05 16:03:14 -0700639 } else {
Danielle Millett2364a222011-12-21 17:02:32 -0500640 // Case where it's a fallback for biometric weak
Jim Miller6edf2632011-09-05 16:03:14 -0700641 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
642 setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
Danielle Millett044a0a72011-11-07 15:42:12 -0500643 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500644 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
645 0, 0, 0, 0, 0, 0, 0);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700646 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700647 // Add the password to the password history. We assume all
648 // password
649 // hashes have the same length for simplicity of implementation.
650 String passwordHistory = getString(PASSWORD_HISTORY_KEY);
651 if (passwordHistory == null) {
652 passwordHistory = new String();
653 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700654 int passwordHistoryLength = getRequestedPasswordHistoryLength();
655 if (passwordHistoryLength == 0) {
656 passwordHistory = "";
657 } else {
658 passwordHistory = new String(hash) + "," + passwordHistory;
659 // Cut it to contain passwordHistoryLength hashes
660 // and passwordHistoryLength -1 commas.
661 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
662 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
663 .length()));
664 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700665 setString(PASSWORD_HISTORY_KEY, passwordHistory);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800666 } else {
Brian Carlstrome2afc242011-06-02 16:21:55 -0700667 // Conditionally reset the keystore if empty. If
668 // non-empty, we are just switching key guard type
669 if (keyStore.isEmpty()) {
670 keyStore.reset();
671 }
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800672 dpm.setActivePasswordState(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700673 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
Jim Miller31f90b62010-01-20 13:35:20 -0800674 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800675 } catch (FileNotFoundException fnfe) {
676 // Cant do much, unless we want to fail over to using the settings provider
677 Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename);
678 } catch (IOException ioe) {
679 // Cant do much
680 Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename);
681 }
682 }
683
Jim Millercd709882010-03-25 18:24:02 -0700684 /**
685 * Retrieves the quality mode we're in.
686 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
687 *
688 * @return stored password quality
689 */
690 public int getKeyguardStoredPasswordQuality() {
Jim Miller6edf2632011-09-05 16:03:14 -0700691 int quality =
692 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
693 // If the user has chosen to use weak biometric sensor, then return the backup locking
694 // method and treat biometric as a special case.
695 if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
696 quality =
697 (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
698 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
699 }
700 return quality;
701 }
702
Danielle Millett58396982011-09-30 13:55:07 -0400703 /**
704 * @return true if the lockscreen method is set to biometric weak
705 */
Jim Miller6edf2632011-09-05 16:03:14 -0700706 public boolean usingBiometricWeak() {
707 int quality =
708 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
709 return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
Jim Miller69aa4a92009-12-22 19:03:28 -0800710 }
711
712 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 * Deserialize a pattern.
714 * @param string The pattern serialized with {@link #patternToString}
715 * @return The pattern.
716 */
717 public static List<LockPatternView.Cell> stringToPattern(String string) {
718 List<LockPatternView.Cell> result = Lists.newArrayList();
719
720 final byte[] bytes = string.getBytes();
721 for (int i = 0; i < bytes.length; i++) {
722 byte b = bytes[i];
723 result.add(LockPatternView.Cell.of(b / 3, b % 3));
724 }
725 return result;
726 }
727
728 /**
729 * Serialize a pattern.
730 * @param pattern The pattern.
731 * @return The pattern in string form.
732 */
733 public static String patternToString(List<LockPatternView.Cell> pattern) {
734 if (pattern == null) {
735 return "";
736 }
737 final int patternSize = pattern.size();
738
739 byte[] res = new byte[patternSize];
740 for (int i = 0; i < patternSize; i++) {
741 LockPatternView.Cell cell = pattern.get(i);
742 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
743 }
744 return new String(res);
745 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 /*
748 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
749 * at least a second level of protection. First level is that the file
750 * is in a location only readable by the system process.
751 * @param pattern the gesture pattern.
752 * @return the hash of the pattern in a byte array.
753 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800754 private static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 if (pattern == null) {
756 return null;
757 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 final int patternSize = pattern.size();
760 byte[] res = new byte[patternSize];
761 for (int i = 0; i < patternSize; i++) {
762 LockPatternView.Cell cell = pattern.get(i);
763 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
764 }
765 try {
766 MessageDigest md = MessageDigest.getInstance("SHA-1");
767 byte[] hash = md.digest(res);
768 return hash;
769 } catch (NoSuchAlgorithmException nsa) {
770 return res;
771 }
772 }
773
Jim Miller11b019d2010-01-20 16:34:45 -0800774 private String getSalt() {
775 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
776 if (salt == 0) {
777 try {
778 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
779 setLong(LOCK_PASSWORD_SALT_KEY, salt);
780 Log.v(TAG, "Initialized lock password salt");
781 } catch (NoSuchAlgorithmException e) {
782 // Throw an exception rather than storing a password we'll never be able to recover
783 throw new IllegalStateException("Couldn't get SecureRandom number", e);
784 }
785 }
786 return Long.toHexString(salt);
787 }
788
Jim Miller69aa4a92009-12-22 19:03:28 -0800789 /*
790 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
791 * Not the most secure, but it is at least a second level of protection. First level is that
792 * the file is in a location only readable by the system process.
793 * @param password the gesture pattern.
794 * @return the hash of the pattern in a byte array.
795 */
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700796 public byte[] passwordToHash(String password) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800797 if (password == null) {
798 return null;
799 }
800 String algo = null;
801 byte[] hashed = null;
802 try {
Jim Miller11b019d2010-01-20 16:34:45 -0800803 byte[] saltedPassword = (password + getSalt()).getBytes();
Jim Miller69aa4a92009-12-22 19:03:28 -0800804 byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
805 byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
806 hashed = (toHex(sha1) + toHex(md5)).getBytes();
807 } catch (NoSuchAlgorithmException e) {
808 Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
809 }
810 return hashed;
811 }
812
813 private static String toHex(byte[] ary) {
814 final String hex = "0123456789ABCDEF";
815 String ret = "";
816 for (int i = 0; i < ary.length; i++) {
817 ret += hex.charAt((ary[i] >> 4) & 0xf);
818 ret += hex.charAt(ary[i] & 0xf);
819 }
820 return ret;
821 }
822
823 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400824 * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
Jim Miller69aa4a92009-12-22 19:03:28 -0800825 */
826 public boolean isLockPasswordEnabled() {
827 long mode = getLong(PASSWORD_TYPE_KEY, 0);
Danielle Millett73da5fe2011-09-13 16:20:05 -0400828 long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
829 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
830 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
831 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
832 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
833 final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
834 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
835 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
836 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
837
838 return savedPasswordExists() && (passwordEnabled ||
Danielle Millett58396982011-09-30 13:55:07 -0400839 (usingBiometricWeak() && backupEnabled));
Jim Miller69aa4a92009-12-22 19:03:28 -0800840 }
841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400843 * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 */
845 public boolean isLockPatternEnabled() {
Danielle Millett73da5fe2011-09-13 16:20:05 -0400846 final boolean backupEnabled =
847 getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
848 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
849
Jim Millera4edd152012-01-06 18:24:04 -0800850 return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
Danielle Millett73da5fe2011-09-13 16:20:05 -0400851 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
852 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
Danielle Millett58396982011-09-30 13:55:07 -0400853 (usingBiometricWeak() && backupEnabled));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855
856 /**
Danielle Millett58396982011-09-30 13:55:07 -0400857 * @return Whether biometric weak lock is installed and that the front facing camera exists
Jim Miller6edf2632011-09-05 16:03:14 -0700858 */
Danielle Millett58396982011-09-30 13:55:07 -0400859 public boolean isBiometricWeakInstalled() {
Danielle Millett58396982011-09-30 13:55:07 -0400860 // Check that it's installed
861 PackageManager pm = mContext.getPackageManager();
862 try {
863 pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
864 } catch (PackageManager.NameNotFoundException e) {
865 return false;
866 }
867
868 // Check that the camera is enabled
869 if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
870 return false;
871 }
872 if (getDevicePolicyManager().getCameraDisabled(null)) {
873 return false;
874 }
875
876
877 return true;
Jim Miller6edf2632011-09-05 16:03:14 -0700878 }
879
880 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 * Set whether the lock pattern is enabled.
882 */
883 public void setLockPatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800884 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
886
887 /**
888 * @return Whether the visible pattern is enabled.
889 */
890 public boolean isVisiblePatternEnabled() {
Jim Millera4edd152012-01-06 18:24:04 -0800891 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
893
894 /**
895 * Set whether the visible pattern is enabled.
896 */
897 public void setVisiblePatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800898 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 }
900
901 /**
902 * @return Whether tactile feedback for the pattern is enabled.
903 */
904 public boolean isTactileFeedbackEnabled() {
Jim Millera4edd152012-01-06 18:24:04 -0800905 return getBoolean(Settings.Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 }
907
908 /**
909 * Set whether tactile feedback for the pattern is enabled.
910 */
911 public void setTactileFeedbackEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800912 setBoolean(Settings.Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 }
914
915 /**
916 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
917 * pattern until the deadline has passed.
918 * @return the chosen deadline.
919 */
920 public long setLockoutAttemptDeadline() {
921 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
922 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
923 return deadline;
924 }
925
926 /**
927 * @return The elapsed time in millis in the future when the user is allowed to
928 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
929 * enter a pattern.
930 */
931 public long getLockoutAttemptDeadline() {
932 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
933 final long now = SystemClock.elapsedRealtime();
934 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
935 return 0L;
936 }
937 return deadline;
938 }
939
940 /**
941 * @return Whether the user is permanently locked out until they verify their
942 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
943 * attempts.
944 */
945 public boolean isPermanentlyLocked() {
Jim Millera4edd152012-01-06 18:24:04 -0800946 return getBoolean(LOCKOUT_PERMANENT_KEY, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 }
948
949 /**
950 * Set the state of whether the device is permanently locked, meaning the user
Karl Rosaen678771b2009-08-21 14:00:26 -0700951 * must authenticate via other means.
952 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 * @param locked Whether the user is permanently locked out until they verify their
954 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
955 * attempts.
956 */
957 public void setPermanentlyLocked(boolean locked) {
958 setBoolean(LOCKOUT_PERMANENT_KEY, locked);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
960
John Wang0f7b3f82011-05-31 11:20:55 -0700961 public boolean isEmergencyCallCapable() {
962 return mContext.getResources().getBoolean(
963 com.android.internal.R.bool.config_voice_capable);
964 }
965
966 public boolean isPukUnlockScreenEnable() {
967 return mContext.getResources().getBoolean(
968 com.android.internal.R.bool.config_enable_puk_unlock_screen);
969 }
970
Jim Miller1f56edc2011-11-07 19:00:48 -0800971 public boolean isEmergencyCallEnabledWhileSimLocked() {
972 return mContext.getResources().getBoolean(
973 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
974 }
975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 /**
977 * @return A formatted string of the next alarm (for showing on the lock screen),
978 * or null if there is no next alarm.
979 */
980 public String getNextAlarm() {
981 String nextAlarm = Settings.System.getString(mContentResolver,
982 Settings.System.NEXT_ALARM_FORMATTED);
983 if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
984 return null;
985 }
986 return nextAlarm;
987 }
988
Jim Millera4edd152012-01-06 18:24:04 -0800989 private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 return 1 ==
Jim Millera4edd152012-01-06 18:24:04 -0800991 android.provider.Settings.Secure.getInt(mContentResolver, secureSettingKey,
992 defaultValue ? 1 : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 }
994
Amith Yamasani156c4352010-03-05 17:10:03 -0800995 private void setBoolean(String secureSettingKey, boolean enabled) {
996 android.provider.Settings.Secure.putInt(mContentResolver, secureSettingKey,
997 enabled ? 1 : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
999
Amith Yamasani156c4352010-03-05 17:10:03 -08001000 private long getLong(String secureSettingKey, long def) {
1001 return android.provider.Settings.Secure.getLong(mContentResolver, secureSettingKey, def);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 }
1003
Amith Yamasani156c4352010-03-05 17:10:03 -08001004 private void setLong(String secureSettingKey, long value) {
1005 android.provider.Settings.Secure.putLong(mContentResolver, secureSettingKey, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 }
1007
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001008 private String getString(String secureSettingKey) {
1009 return android.provider.Settings.Secure.getString(mContentResolver, secureSettingKey);
1010 }
1011
1012 private void setString(String secureSettingKey, String value) {
1013 android.provider.Settings.Secure.putString(mContentResolver, secureSettingKey, value);
1014 }
1015
Jim Miller69aa4a92009-12-22 19:03:28 -08001016 public boolean isSecure() {
Jim Millercd709882010-03-25 18:24:02 -07001017 long mode = getKeyguardStoredPasswordQuality();
1018 final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1019 final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1020 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001021 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1022 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Jim Millercd709882010-03-25 18:24:02 -07001023 final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
Danielle Millett73da5fe2011-09-13 16:20:05 -04001024 || isPassword && savedPasswordExists();
Jim Miller69aa4a92009-12-22 19:03:28 -08001025 return secure;
1026 }
Jim Miller69ac9882010-02-24 15:35:05 -08001027
1028 /**
John Wang0f7b3f82011-05-31 11:20:55 -07001029 * Sets the emergency button visibility based on isEmergencyCallCapable().
1030 *
1031 * If the emergency button is visible, sets the text on the emergency button
1032 * to indicate what action will be taken.
1033 *
Jim Miller69ac9882010-02-24 15:35:05 -08001034 * If there's currently a call in progress, the button will take them to the call
1035 * @param button the button to update
Jim Miller3f5f83b2011-09-26 15:17:05 -07001036 * @param the phone state:
1037 * {@link TelephonyManager#CALL_STATE_IDLE}
1038 * {@link TelephonyManager#CALL_STATE_RINGING}
1039 * {@link TelephonyManager#CALL_STATE_OFFHOOK}
Jim Miller1f56edc2011-11-07 19:00:48 -08001040 * @param shown indicates whether the given screen wants the emergency button to show at all
Jim Miller69ac9882010-02-24 15:35:05 -08001041 */
Jim Miller1f56edc2011-11-07 19:00:48 -08001042 public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
1043 if (isEmergencyCallCapable() && shown) {
John Wang0f7b3f82011-05-31 11:20:55 -07001044 button.setVisibility(View.VISIBLE);
1045 } else {
1046 button.setVisibility(View.GONE);
1047 return;
1048 }
1049
Jim Miller69ac9882010-02-24 15:35:05 -08001050 int textId;
Jim Miller3f5f83b2011-09-26 15:17:05 -07001051 if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
Jim Miller69ac9882010-02-24 15:35:05 -08001052 // show "return to call" text and show phone icon
1053 textId = R.string.lockscreen_return_to_call;
1054 int phoneCallIcon = R.drawable.stat_sys_phone_call;
1055 button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
1056 } else {
1057 textId = R.string.lockscreen_emergency_call;
1058 int emergencyIcon = R.drawable.ic_emergency;
1059 button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
1060 }
1061 button.setText(textId);
1062 }
1063
1064 /**
1065 * Resumes a call in progress. Typically launched from the EmergencyCall button
1066 * on various lockscreens.
1067 *
1068 * @return true if we were able to tell InCallScreen to show.
1069 */
1070 public boolean resumeCall() {
1071 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
1072 try {
1073 if (phone != null && phone.showCallScreen()) {
1074 return true;
1075 }
1076 } catch (RemoteException e) {
1077 // What can we do?
1078 }
1079 return false;
1080 }
Danielle Millett044a0a72011-11-07 15:42:12 -05001081
1082 private void finishBiometricWeak() {
1083 setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
1084
1085 // Launch intent to show final screen, this also
1086 // moves the temporary gallery to the actual gallery
1087 Intent intent = new Intent();
1088 intent.setClassName("com.android.facelock",
1089 "com.android.facelock.SetupEndScreen");
1090 mContext.startActivity(intent);
1091 }
1092
Jim Millera4edd152012-01-06 18:24:04 -08001093 public void setPowerButtonInstantlyLocks(boolean enabled) {
1094 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
1095 }
1096
1097 public boolean getPowerButtonInstantlyLocks() {
1098 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
1099 }
1100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101}