blob: 74b1fddf9defd2d2699f2234499f3c037055ce35 [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;
Adrian Roosedad7b22014-07-13 14:38:22 +020021import android.app.AlarmManager;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080022import android.app.admin.DevicePolicyManager;
Adrian Roos82142c22014-03-27 14:56:59 +010023import android.app.trust.TrustManager;
Jim Miller51117262012-11-04 17:58:09 -080024import android.appwidget.AppWidgetManager;
Adrian Roos82142c22014-03-27 14:56:59 +010025import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080027import android.content.Context;
Steven Ross329979c2011-09-28 11:42:56 -040028import android.content.Intent;
Danielle Millett58396982011-09-30 13:55:07 -040029import android.content.pm.PackageManager;
Jason parksf7b3cd42011-01-27 09:28:25 -060030import android.os.IBinder;
Jim Miller69ac9882010-02-24 15:35:05 -080031import android.os.RemoteException;
32import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070034import android.os.UserHandle;
Jason parksf7b3cd42011-01-27 09:28:25 -060035import android.os.storage.IMountService;
Paul Lawrence8e397362014-01-27 15:22:30 -080036import android.os.storage.StorageManager;
Santos Cordon0bae09f2014-07-07 14:53:10 -070037import android.phone.PhoneManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.text.TextUtils;
40import android.util.Log;
Jim Miller51117262012-11-04 17:58:09 -080041import android.view.IWindowManager;
John Wang0f7b3f82011-05-31 11:20:55 -070042import android.view.View;
Jim Miller69ac9882010-02-24 15:35:05 -080043import android.widget.Button;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Michael Jurka1254f2f2012-10-25 11:44:31 -070045import com.android.internal.R;
Michael Jurka1254f2f2012-10-25 11:44:31 -070046import com.google.android.collect.Lists;
Michael Jurkaaa2859a2012-10-24 12:46:49 -070047
Brian Carlstrom929a1c22011-02-01 21:54:09 -080048import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080050import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010051import java.util.ArrayList;
52import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import java.util.List;
54
55/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070056 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 */
58public class LockPatternUtils {
59
60 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040061 private static final boolean DEBUG = false;
Jim Miller69aa4a92009-12-22 19:03:28 -080062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 /**
64 * The maximum number of incorrect attempts before the user is prevented
65 * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
66 */
67 public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
68
69 /**
70 * The number of incorrect attempts before which we fall back on an alternative
71 * method of verifying the user, and resetting their lock pattern.
72 */
73 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
74
75 /**
76 * How long the user is prevented from trying again after entering the
77 * wrong pattern too many times.
78 */
79 public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
80
81 /**
82 * The interval of the countdown for showing progress of the lockout.
83 */
84 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
85
Jim Miller4f369952011-08-19 18:29:22 -070086
87 /**
88 * This dictates when we start telling the user that continued failed attempts will wipe
89 * their device.
90 */
91 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
92
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 /**
94 * The minimum number of dots in a valid pattern.
95 */
96 public static final int MIN_LOCK_PATTERN_SIZE = 4;
97
98 /**
99 * The minimum number of dots the user must include in a wrong pattern
100 * attempt for it to be counted against the counts that affect
101 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
102 */
Jim Miller4f369952011-08-19 18:29:22 -0700103 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
Danielle Millett925a7d82012-03-19 18:02:20 -0400105 /**
Adam Cohenf7522022012-10-03 20:03:18 -0700106 * Tells the keyguard to show the user switcher when the keyguard is created.
107 */
108 public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
109
110 /**
111 * Tells the keyguard to show the security challenge when the keyguard is created.
112 */
113 public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
114
115 /**
Michael Jurka76017ca2012-11-06 16:21:09 -0800116 * Tells the keyguard to show the widget with the specified id when the keyguard is created.
117 */
118 public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
119
120 /**
Danielle Millett925a7d82012-03-19 18:02:20 -0400121 * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
122 * be used
123 */
124 public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
125
Michael Jurka1254f2f2012-10-25 11:44:31 -0700126 /**
127 * Pseudo-appwidget id we use to represent the default clock status widget
128 */
129 public static final int ID_DEFAULT_STATUS_WIDGET = -2;
130
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800131 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
132 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
133 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800134 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Jim Miller6edf2632011-09-05 16:03:14 -0700135 public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800136 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
137 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
138 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Jim Miller6edf2632011-09-05 16:03:14 -0700139 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
140 = "lockscreen.biometric_weak_fallback";
Danielle Millett7a072192011-10-03 17:36:01 -0400141 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
142 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800143 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
144 = "lockscreen.power_button_instantly_locks";
Jim Millerf45bb402013-08-20 18:58:32 -0700145 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800147 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700148
Jim Miller187ec582013-04-15 18:27:54 -0700149 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
150 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
151 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
152
Adrian Roos82142c22014-03-27 14:56:59 +0100153 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
154
Jim Miller85516d02014-01-31 17:08:37 -0800155 // Maximum allowed number of repeated or ordered characters in a sequence before we'll
156 // consider it a complex PIN/password.
157 public static final int MAX_ALLOWED_SEQUENCE = 3;
158
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800159 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800161 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700162 private ILockSettings mLockSettingsService;
Jim Milleree82f8f2012-10-01 16:26:18 -0700163
Jim Miller78c48f62013-03-01 15:28:33 -0800164 private final boolean mMultiUserMode;
165
Jim Milleree82f8f2012-10-01 16:26:18 -0700166 // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
167 private static volatile int sCurrentUserId = UserHandle.USER_NULL;
Dianne Hackbornde4c26f2011-07-17 13:42:47 -0700168
Jim Millercd709882010-03-25 18:24:02 -0700169 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800170 if (mDevicePolicyManager == null) {
171 mDevicePolicyManager =
172 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
173 if (mDevicePolicyManager == null) {
174 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
175 new IllegalStateException("Stack trace:"));
176 }
177 }
178 return mDevicePolicyManager;
179 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700180
Adrian Roos82142c22014-03-27 14:56:59 +0100181 private TrustManager getTrustManager() {
182 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
183 if (trust == null) {
184 Log.e(TAG, "Can't get TrustManagerService: is it running?",
185 new IllegalStateException("Stack trace:"));
186 }
187 return trust;
188 }
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 /**
191 * @param contentResolver Used to look up and save settings.
192 */
Jim Miller31f90b62010-01-20 13:35:20 -0800193 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800194 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800195 mContentResolver = context.getContentResolver();
Jim Miller78c48f62013-03-01 15:28:33 -0800196
197 // If this is being called by the system or by an application like keyguard that
198 // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
199 // mode where calls are for the current user rather than the user of the calling process.
200 mMultiUserMode = context.checkCallingOrSelfPermission(
201 Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700202 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800203
Amith Yamasani52c489c2012-03-28 11:42:42 -0700204 private ILockSettings getLockSettings() {
205 if (mLockSettingsService == null) {
Adrian Roos4f788452014-05-22 20:45:59 +0200206 mLockSettingsService = LockPatternUtilsCache.getInstance(
207 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings")));
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700208 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700209 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 }
211
Jim Miller31f90b62010-01-20 13:35:20 -0800212 public int getRequestedMinimumPasswordLength() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700213 return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800214 }
215
Jim Miller31f90b62010-01-20 13:35:20 -0800216 /**
217 * Gets the device policy password mode. If the mode is non-specific, returns
218 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800219 */
Jim Millercd709882010-03-25 18:24:02 -0700220 public int getRequestedPasswordQuality() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700221 return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800222 }
223
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700224 public int getRequestedPasswordHistoryLength() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700225 return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700226 }
227
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700228 public int getRequestedPasswordMinimumLetters() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700229 return getDevicePolicyManager().getPasswordMinimumLetters(null,
230 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700231 }
232
233 public int getRequestedPasswordMinimumUpperCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700234 return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
235 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700236 }
237
238 public int getRequestedPasswordMinimumLowerCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700239 return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
240 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700241 }
242
243 public int getRequestedPasswordMinimumNumeric() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700244 return getDevicePolicyManager().getPasswordMinimumNumeric(null,
245 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700246 }
247
248 public int getRequestedPasswordMinimumSymbols() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700249 return getDevicePolicyManager().getPasswordMinimumSymbols(null,
250 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700251 }
252
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700253 public int getRequestedPasswordMinimumNonLetter() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700254 return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
255 getCurrentOrCallingUserId());
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700256 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700257
Jim Miller31f90b62010-01-20 13:35:20 -0800258 public void reportFailedPasswordAttempt() {
Adrian Roos4f994eb2014-07-23 15:45:05 +0200259 int userId = getCurrentOrCallingUserId();
260 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
261 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
262 getTrustManager().reportRequireCredentialEntry(userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800263 }
264
265 public void reportSuccessfulPasswordAttempt() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700266 getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
Adrian Roos82142c22014-03-27 14:56:59 +0100267 getTrustManager().reportUnlockAttempt(true /* authenticated */,
268 getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800269 }
270
Amith Yamasani52c489c2012-03-28 11:42:42 -0700271 public void setCurrentUser(int userId) {
Jim Milleree82f8f2012-10-01 16:26:18 -0700272 sCurrentUserId = userId;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700273 }
274
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700275 public int getCurrentUser() {
Jim Milleree82f8f2012-10-01 16:26:18 -0700276 if (sCurrentUserId != UserHandle.USER_NULL) {
Jim Miller25645d82012-09-21 14:47:54 -0700277 // Someone is regularly updating using setCurrentUser() use that value.
Jim Milleree82f8f2012-10-01 16:26:18 -0700278 return sCurrentUserId;
Jim Miller25645d82012-09-21 14:47:54 -0700279 }
280 try {
281 return ActivityManagerNative.getDefault().getCurrentUser().id;
282 } catch (RemoteException re) {
283 return UserHandle.USER_OWNER;
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700284 }
285 }
286
Amith Yamasani52c489c2012-03-28 11:42:42 -0700287 public void removeUser(int userId) {
Jim Miller25645d82012-09-21 14:47:54 -0700288 try {
289 getLockSettings().removeUser(userId);
290 } catch (RemoteException re) {
291 Log.e(TAG, "Couldn't remove lock settings for user " + userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700292 }
293 }
294
295 private int getCurrentOrCallingUserId() {
Jim Miller78c48f62013-03-01 15:28:33 -0800296 if (mMultiUserMode) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700297 // TODO: This is a little inefficient. See if all users of this are able to
298 // handle USER_CURRENT and pass that instead.
299 return getCurrentUser();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700300 } else {
Jim Miller78c48f62013-03-01 15:28:33 -0800301 return UserHandle.getCallingUserId();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700302 }
303 }
304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 /**
306 * Check to see if a pattern matches the saved pattern. If no pattern exists,
307 * always returns true.
308 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800309 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 */
311 public boolean checkPattern(List<LockPatternView.Cell> pattern) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700312 final int userId = getCurrentOrCallingUserId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 try {
Jim Millerde1af082013-09-11 14:58:26 -0700314 return getLockSettings().checkPattern(patternToString(pattern), userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700315 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 return true;
317 }
318 }
319
320 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800321 * Check to see if a password matches the saved password. If no password exists,
322 * always returns true.
323 * @param password The password to check.
324 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800326 public boolean checkPassword(String password) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700327 final int userId = getCurrentOrCallingUserId();
Jim Miller69aa4a92009-12-22 19:03:28 -0800328 try {
Jim Millerde1af082013-09-11 14:58:26 -0700329 return getLockSettings().checkPassword(password, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700330 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800331 return true;
332 }
333 }
334
335 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000336 * Check to see if vold already has the password.
337 * Note that this also clears vold's copy of the password.
338 * @return Whether the vold password matches or not.
339 */
340 public boolean checkVoldPassword() {
341 final int userId = getCurrentOrCallingUserId();
342 try {
343 return getLockSettings().checkVoldPassword(userId);
344 } catch (RemoteException re) {
345 return false;
346 }
347 }
348
349 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700350 * Check to see if a password matches any of the passwords stored in the
351 * password history.
352 *
353 * @param password The password to check.
354 * @return Whether the password matches any in the history.
355 */
356 public boolean checkPasswordHistory(String password) {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400357 String passwordHashString = new String(
358 passwordToHash(password, getCurrentOrCallingUserId()));
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700359 String passwordHistory = getString(PASSWORD_HISTORY_KEY);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700360 if (passwordHistory == null) {
361 return false;
362 }
363 // Password History may be too long...
364 int passwordHashLength = passwordHashString.length();
365 int passwordHistoryLength = getRequestedPasswordHistoryLength();
366 if(passwordHistoryLength == 0) {
367 return false;
368 }
369 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
370 + passwordHistoryLength - 1;
371 if (passwordHistory.length() > neededPasswordHistoryLength) {
372 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
373 }
374 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700375 }
376
377 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800378 * Check to see if the user has stored a lock pattern.
379 * @return Whether a saved pattern exists.
380 */
381 public boolean savedPatternExists() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700382 try {
383 return getLockSettings().havePattern(getCurrentOrCallingUserId());
384 } catch (RemoteException re) {
385 return false;
386 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800387 }
388
389 /**
390 * Check to see if the user has stored a lock pattern.
391 * @return Whether a saved pattern exists.
392 */
393 public boolean savedPasswordExists() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700394 try {
395 return getLockSettings().havePassword(getCurrentOrCallingUserId());
396 } catch (RemoteException re) {
397 return false;
398 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800399 }
400
401 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700402 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
403 * currently cleared.
404 *
405 * @return True if the user has ever chosen a pattern.
406 */
407 public boolean isPatternEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800408 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700409 }
410
411 /**
Danielle Millett7a072192011-10-03 17:36:01 -0400412 * Return true if the user has ever chosen biometric weak. This is true even if biometric
413 * weak is not current set.
414 *
415 * @return True if the user has ever chosen biometric weak.
416 */
417 public boolean isBiometricWeakEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800418 return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
Danielle Millett7a072192011-10-03 17:36:01 -0400419 }
420
421 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700422 * Used by device policy manager to validate the current password
423 * information it has.
424 */
425 public int getActivePasswordQuality() {
Jim Millercd709882010-03-25 18:24:02 -0700426 int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400427 // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
428 // return biometric_weak if that is being used instead of the backup
429 int quality =
430 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
431 switch (quality) {
Jim Millercd709882010-03-25 18:24:02 -0700432 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700433 if (isLockPatternEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700434 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700435 }
Jim Millercd709882010-03-25 18:24:02 -0700436 break;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400437 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
438 if (isBiometricWeakInstalled()) {
439 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
440 }
441 break;
Jim Millercd709882010-03-25 18:24:02 -0700442 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700443 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700444 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700445 }
Jim Millercd709882010-03-25 18:24:02 -0700446 break;
Jim Miller85516d02014-01-31 17:08:37 -0800447 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
448 if (isLockPasswordEnabled()) {
449 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
450 }
451 break;
Jim Millercd709882010-03-25 18:24:02 -0700452 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700453 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700454 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700455 }
Jim Millercd709882010-03-25 18:24:02 -0700456 break;
457 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
458 if (isLockPasswordEnabled()) {
459 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
460 }
461 break;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700462 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
463 if (isLockPasswordEnabled()) {
464 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
465 }
466 break;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700467 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400468
Jim Millercd709882010-03-25 18:24:02 -0700469 return activePasswordQuality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700470 }
Jim Millercd709882010-03-25 18:24:02 -0700471
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700472 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800473 * Clear any lock pattern or password.
474 */
Steven Ross329979c2011-09-28 11:42:56 -0400475 public void clearLock(boolean isFallback) {
476 if(!isFallback) deleteGallery();
Jim Millercd709882010-03-25 18:24:02 -0700477 saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800478 setLockPatternEnabled(false);
479 saveLockPattern(null);
Jim Miller93708af2012-01-25 18:26:12 -0800480 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700481 setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800482 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800483
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800484 /**
Jim Miller2a98a4c2010-11-19 18:49:26 -0800485 * Disable showing lock screen at all when the DevicePolicyManager allows it.
486 * This is only meaningful if pattern, pin or password are not set.
487 *
488 * @param disable Disables lock screen when true
489 */
490 public void setLockScreenDisabled(boolean disable) {
491 setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
492 }
493
494 /**
495 * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
496 * show LockScreen or go straight to the home screen.
497 *
498 * @return true if lock screen is can be disabled
499 */
500 public boolean isLockScreenDisabled() {
501 return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
502 }
503
504 /**
Steven Ross3553c292011-09-30 15:48:40 -0400505 * Calls back SetupFaceLock to delete the temporary gallery file
Steven Ross329979c2011-09-28 11:42:56 -0400506 */
507 public void deleteTempGallery() {
Danielle Millett574e49e2012-03-27 16:17:10 -0400508 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
Steven Ross3553c292011-09-30 15:48:40 -0400509 intent.putExtra("deleteTempGallery", true);
Danielle Millett574e49e2012-03-27 16:17:10 -0400510 mContext.sendBroadcast(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400511 }
512
513 /**
514 * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
515 */
516 void deleteGallery() {
Danielle Millett58396982011-09-30 13:55:07 -0400517 if(usingBiometricWeak()) {
Danielle Millett574e49e2012-03-27 16:17:10 -0400518 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
Steven Ross329979c2011-09-28 11:42:56 -0400519 intent.putExtra("deleteGallery", true);
Danielle Millett574e49e2012-03-27 16:17:10 -0400520 mContext.sendBroadcast(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400521 }
522 }
523
524 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700525 * Save a lock pattern.
526 * @param pattern The new pattern to save.
Danielle Millett2364a222011-12-21 17:02:32 -0500527 */
528 public void saveLockPattern(List<LockPatternView.Cell> pattern) {
529 this.saveLockPattern(pattern, false);
530 }
531
532 /**
533 * Save a lock pattern.
534 * @param pattern The new pattern to save.
Jim Miller6edf2632011-09-05 16:03:14 -0700535 * @param isFallback Specifies if this is a fallback to biometric weak
536 */
537 public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 try {
Adrian Roos82142c22014-03-27 14:56:59 +0100539 int userId = getCurrentOrCallingUserId();
540 getLockSettings().setLockPattern(patternToString(pattern), userId);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800541 DevicePolicyManager dpm = getDevicePolicyManager();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800542 if (pattern != null) {
Paul Lawrence8e397362014-01-27 15:22:30 -0800543
Adrian Roos82142c22014-03-27 14:56:59 +0100544 int userHandle = userId;
Paul Lawrence8e397362014-01-27 15:22:30 -0800545 if (userHandle == UserHandle.USER_OWNER) {
546 String stringPattern = patternToString(pattern);
547 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
548 }
549
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800550 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
Jim Miller6edf2632011-09-05 16:03:14 -0700551 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400552 deleteGallery();
Jim Miller6edf2632011-09-05 16:03:14 -0700553 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett2364a222011-12-21 17:02:32 -0500554 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
Adrian Roos82142c22014-03-27 14:56:59 +0100555 pattern.size(), 0, 0, 0, 0, 0, 0, userId);
Jim Miller6edf2632011-09-05 16:03:14 -0700556 } else {
557 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
558 setLong(PASSWORD_TYPE_ALTERNATE_KEY,
559 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett044a0a72011-11-07 15:42:12 -0500560 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500561 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
Adrian Roos82142c22014-03-27 14:56:59 +0100562 0, 0, 0, 0, 0, 0, 0, userId);
Jim Miller6edf2632011-09-05 16:03:14 -0700563 }
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800564 } else {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700565 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
Adrian Roos82142c22014-03-27 14:56:59 +0100566 0, 0, 0, 0, 0, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800567 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700568 } catch (RemoteException re) {
569 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 }
571 }
572
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700573 private void updateCryptoUserInfo() {
574 int userId = getCurrentOrCallingUserId();
575 if (userId != UserHandle.USER_OWNER) {
576 return;
577 }
578
579 final String ownerInfo = isOwnerInfoEnabled() ? getOwnerInfo(userId) : "";
580
581 IBinder service = ServiceManager.getService("mount");
582 if (service == null) {
583 Log.e(TAG, "Could not find the mount service to update the user info");
584 return;
585 }
586
587 IMountService mountService = IMountService.Stub.asInterface(service);
588 try {
589 Log.d(TAG, "Setting owner info");
590 mountService.setField("OwnerInfo", ownerInfo);
591 } catch (RemoteException e) {
592 Log.e(TAG, "Error changing user info", e);
593 }
594 }
595
Jim Miller187ec582013-04-15 18:27:54 -0700596 public void setOwnerInfo(String info, int userId) {
597 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700598 updateCryptoUserInfo();
Jim Miller187ec582013-04-15 18:27:54 -0700599 }
600
601 public void setOwnerInfoEnabled(boolean enabled) {
602 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700603 updateCryptoUserInfo();
Jim Miller187ec582013-04-15 18:27:54 -0700604 }
605
606 public String getOwnerInfo(int userId) {
607 return getString(LOCK_SCREEN_OWNER_INFO);
608 }
609
610 public boolean isOwnerInfoEnabled() {
611 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
612 }
613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700615 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800616 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700617 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800618 boolean hasDigit = false;
619 boolean hasNonDigit = false;
620 final int len = password.length();
621 for (int i = 0; i < len; i++) {
622 if (Character.isDigit(password.charAt(i))) {
623 hasDigit = true;
624 } else {
625 hasNonDigit = true;
626 }
627 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800628
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700629 if (hasNonDigit && hasDigit) {
630 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800631 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800632 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700633 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800634 }
635 if (hasDigit) {
Jim Miller85516d02014-01-31 17:08:37 -0800636 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
637 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
638 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800639 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700640 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800641 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800642
Jim Miller85516d02014-01-31 17:08:37 -0800643 private static int categoryChar(char c) {
644 if ('a' <= c && c <= 'z') return 0;
645 if ('A' <= c && c <= 'Z') return 1;
646 if ('0' <= c && c <= '9') return 2;
647 return 3;
648 }
649
650 private static int maxDiffCategory(int category) {
651 if (category == 0 || category == 1) return 1;
652 else if (category == 2) return 10;
653 return 0;
654 }
655
656 /*
657 * Returns the maximum length of a sequential characters. A sequence is defined as
658 * monotonically increasing characters with a constant interval or the same character repeated.
659 *
660 * For example:
661 * maxLengthSequence("1234") == 4
662 * maxLengthSequence("1234abc") == 4
663 * maxLengthSequence("aabc") == 3
664 * maxLengthSequence("qwertyuio") == 1
665 * maxLengthSequence("@ABC") == 3
666 * maxLengthSequence(";;;;") == 4 (anything that repeats)
667 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
668 *
669 * @param string the pass
670 * @return the number of sequential letters or digits
671 */
672 public static int maxLengthSequence(String string) {
673 if (string.length() == 0) return 0;
674 char previousChar = string.charAt(0);
675 int category = categoryChar(previousChar); //current category of the sequence
676 int diff = 0; //difference between two consecutive characters
677 boolean hasDiff = false; //if we are currently targeting a sequence
678 int maxLength = 0; //maximum length of a sequence already found
679 int startSequence = 0; //where the current sequence started
680 for (int current = 1; current < string.length(); current++) {
681 char currentChar = string.charAt(current);
682 int categoryCurrent = categoryChar(currentChar);
683 int currentDiff = (int) currentChar - (int) previousChar;
684 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
685 maxLength = Math.max(maxLength, current - startSequence);
686 startSequence = current;
687 hasDiff = false;
688 category = categoryCurrent;
689 }
690 else {
691 if(hasDiff && currentDiff != diff) {
692 maxLength = Math.max(maxLength, current - startSequence);
693 startSequence = current - 1;
694 }
695 diff = currentDiff;
696 hasDiff = true;
697 }
698 previousChar = currentChar;
699 }
700 maxLength = Math.max(maxLength, string.length() - startSequence);
701 return maxLength;
702 }
703
Jason parksf7b3cd42011-01-27 09:28:25 -0600704 /** Update the encryption password if it is enabled **/
Paul Lawrence8e397362014-01-27 15:22:30 -0800705 private void updateEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600706 DevicePolicyManager dpm = getDevicePolicyManager();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700707 if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
708 != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600709 return;
710 }
711
712 IBinder service = ServiceManager.getService("mount");
713 if (service == null) {
714 Log.e(TAG, "Could not find the mount service to update the encryption password");
715 return;
716 }
717
718 IMountService mountService = IMountService.Stub.asInterface(service);
719 try {
Paul Lawrence8e397362014-01-27 15:22:30 -0800720 mountService.changeEncryptionPassword(type, password);
Jason parksf7b3cd42011-01-27 09:28:25 -0600721 } catch (RemoteException e) {
722 Log.e(TAG, "Error changing encryption password", e);
723 }
724 }
725
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800726 /**
Jim Millercd709882010-03-25 18:24:02 -0700727 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800728 * as the requested mode, but will adjust the mode to be as good as the
729 * pattern.
Jim Miller69aa4a92009-12-22 19:03:28 -0800730 * @param password The password to save
Jim Millercd709882010-03-25 18:24:02 -0700731 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Jim Miller69aa4a92009-12-22 19:03:28 -0800732 */
Jim Millercd709882010-03-25 18:24:02 -0700733 public void saveLockPassword(String password, int quality) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700734 this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700735 }
736
737 /**
738 * Save a lock password. Does not ensure that the password is as good
739 * as the requested mode, but will adjust the mode to be as good as the
740 * pattern.
741 * @param password The password to save
742 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
743 * @param isFallback Specifies if this is a fallback to biometric weak
744 */
745 public void saveLockPassword(String password, int quality, boolean isFallback) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700746 saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
747 }
748
749 /**
750 * Save a lock password. Does not ensure that the password is as good
751 * as the requested mode, but will adjust the mode to be as good as the
752 * pattern.
753 * @param password The password to save
754 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
755 * @param isFallback Specifies if this is a fallback to biometric weak
756 * @param userHandle The userId of the user to change the password for
757 */
758 public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800759 try {
Jim Millerde1af082013-09-11 14:58:26 -0700760 getLockSettings().setLockPassword(password, userHandle);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800761 DevicePolicyManager dpm = getDevicePolicyManager();
Paul Lawrenceba45bcb2014-07-02 15:38:35 -0700762 if (!TextUtils.isEmpty(password)) {
Paul Lawrence8e397362014-01-27 15:22:30 -0800763 int computedQuality = computePasswordQuality(password);
764
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700765 if (userHandle == UserHandle.USER_OWNER) {
766 // Update the encryption password.
Paul Lawrence8e397362014-01-27 15:22:30 -0800767 int type = computedQuality == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
768 ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD;
769 updateEncryptionPassword(type, password);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700770 }
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700771
Jim Miller6edf2632011-09-05 16:03:14 -0700772 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400773 deleteGallery();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700774 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500775 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
776 int letters = 0;
777 int uppercase = 0;
778 int lowercase = 0;
779 int numbers = 0;
780 int symbols = 0;
781 int nonletter = 0;
782 for (int i = 0; i < password.length(); i++) {
783 char c = password.charAt(i);
784 if (c >= 'A' && c <= 'Z') {
785 letters++;
786 uppercase++;
787 } else if (c >= 'a' && c <= 'z') {
788 letters++;
789 lowercase++;
790 } else if (c >= '0' && c <= '9') {
791 numbers++;
792 nonletter++;
793 } else {
794 symbols++;
795 nonletter++;
796 }
797 }
798 dpm.setActivePasswordState(Math.max(quality, computedQuality),
799 password.length(), letters, uppercase, lowercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700800 numbers, symbols, nonletter, userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500801 } else {
802 // The password is not anything.
803 dpm.setActivePasswordState(
804 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700805 0, 0, 0, 0, 0, 0, 0, userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500806 }
Jim Miller6edf2632011-09-05 16:03:14 -0700807 } else {
Danielle Millett2364a222011-12-21 17:02:32 -0500808 // Case where it's a fallback for biometric weak
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700809 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
810 userHandle);
811 setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
812 userHandle);
Danielle Millett044a0a72011-11-07 15:42:12 -0500813 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500814 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700815 0, 0, 0, 0, 0, 0, 0, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700816 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700817 // Add the password to the password history. We assume all
Paul Lawrence8e397362014-01-27 15:22:30 -0800818 // password hashes have the same length for simplicity of implementation.
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700819 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700820 if (passwordHistory == null) {
821 passwordHistory = new String();
822 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700823 int passwordHistoryLength = getRequestedPasswordHistoryLength();
824 if (passwordHistoryLength == 0) {
825 passwordHistory = "";
826 } else {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400827 byte[] hash = passwordToHash(password, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700828 passwordHistory = new String(hash) + "," + passwordHistory;
829 // Cut it to contain passwordHistoryLength hashes
830 // and passwordHistoryLength -1 commas.
831 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
832 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
833 .length()));
834 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700835 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800836 } else {
Paul Lawrenceba45bcb2014-07-02 15:38:35 -0700837 // Empty password
Paul Lawrence8e397362014-01-27 15:22:30 -0800838 if (userHandle == UserHandle.USER_OWNER) {
Paul Lawrenceba45bcb2014-07-02 15:38:35 -0700839 // Set the encryption password to default.
840 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
Paul Lawrence8e397362014-01-27 15:22:30 -0800841 }
842
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800843 dpm.setActivePasswordState(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700844 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
845 userHandle);
Jim Miller31f90b62010-01-20 13:35:20 -0800846 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700847 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800848 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700849 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800850 }
851 }
852
Jim Millercd709882010-03-25 18:24:02 -0700853 /**
854 * Retrieves the quality mode we're in.
855 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
856 *
857 * @return stored password quality
858 */
859 public int getKeyguardStoredPasswordQuality() {
Jim Miller6edf2632011-09-05 16:03:14 -0700860 int quality =
Jim Miller43120732014-04-14 16:56:08 -0700861 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700862 // If the user has chosen to use weak biometric sensor, then return the backup locking
863 // method and treat biometric as a special case.
864 if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
865 quality =
866 (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
Jim Miller43120732014-04-14 16:56:08 -0700867 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700868 }
869 return quality;
870 }
871
Danielle Millett58396982011-09-30 13:55:07 -0400872 /**
873 * @return true if the lockscreen method is set to biometric weak
874 */
Jim Miller6edf2632011-09-05 16:03:14 -0700875 public boolean usingBiometricWeak() {
876 int quality =
Jim Miller43120732014-04-14 16:56:08 -0700877 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700878 return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
Jim Miller69aa4a92009-12-22 19:03:28 -0800879 }
880
881 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 * Deserialize a pattern.
883 * @param string The pattern serialized with {@link #patternToString}
884 * @return The pattern.
885 */
886 public static List<LockPatternView.Cell> stringToPattern(String string) {
887 List<LockPatternView.Cell> result = Lists.newArrayList();
888
889 final byte[] bytes = string.getBytes();
890 for (int i = 0; i < bytes.length; i++) {
891 byte b = bytes[i];
892 result.add(LockPatternView.Cell.of(b / 3, b % 3));
893 }
894 return result;
895 }
896
897 /**
898 * Serialize a pattern.
899 * @param pattern The pattern.
900 * @return The pattern in string form.
901 */
902 public static String patternToString(List<LockPatternView.Cell> pattern) {
903 if (pattern == null) {
904 return "";
905 }
906 final int patternSize = pattern.size();
907
908 byte[] res = new byte[patternSize];
909 for (int i = 0; i < patternSize; i++) {
910 LockPatternView.Cell cell = pattern.get(i);
911 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
912 }
913 return new String(res);
914 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 /*
917 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
918 * at least a second level of protection. First level is that the file
919 * is in a location only readable by the system process.
920 * @param pattern the gesture pattern.
921 * @return the hash of the pattern in a byte array.
922 */
Jim Millerde1af082013-09-11 14:58:26 -0700923 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 if (pattern == null) {
925 return null;
926 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 final int patternSize = pattern.size();
929 byte[] res = new byte[patternSize];
930 for (int i = 0; i < patternSize; i++) {
931 LockPatternView.Cell cell = pattern.get(i);
932 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
933 }
934 try {
935 MessageDigest md = MessageDigest.getInstance("SHA-1");
936 byte[] hash = md.digest(res);
937 return hash;
938 } catch (NoSuchAlgorithmException nsa) {
939 return res;
940 }
941 }
942
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400943 private String getSalt(int userId) {
944 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800945 if (salt == 0) {
946 try {
947 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400948 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
949 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800950 } catch (NoSuchAlgorithmException e) {
951 // Throw an exception rather than storing a password we'll never be able to recover
952 throw new IllegalStateException("Couldn't get SecureRandom number", e);
953 }
954 }
955 return Long.toHexString(salt);
956 }
957
Jim Miller69aa4a92009-12-22 19:03:28 -0800958 /*
959 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
960 * Not the most secure, but it is at least a second level of protection. First level is that
961 * the file is in a location only readable by the system process.
962 * @param password the gesture pattern.
963 * @return the hash of the pattern in a byte array.
964 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400965 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800966 if (password == null) {
967 return null;
968 }
969 String algo = null;
970 byte[] hashed = null;
971 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400972 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Jim Miller69aa4a92009-12-22 19:03:28 -0800973 byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
974 byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
975 hashed = (toHex(sha1) + toHex(md5)).getBytes();
976 } catch (NoSuchAlgorithmException e) {
977 Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
978 }
979 return hashed;
980 }
981
982 private static String toHex(byte[] ary) {
983 final String hex = "0123456789ABCDEF";
984 String ret = "";
985 for (int i = 0; i < ary.length; i++) {
986 ret += hex.charAt((ary[i] >> 4) & 0xf);
987 ret += hex.charAt(ary[i] & 0xf);
988 }
989 return ret;
990 }
991
992 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400993 * @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 -0800994 */
995 public boolean isLockPasswordEnabled() {
996 long mode = getLong(PASSWORD_TYPE_KEY, 0);
Danielle Millett73da5fe2011-09-13 16:20:05 -0400997 long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
998 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
999 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001000 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001001 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1002 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
1003 final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1004 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001005 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001006 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1007 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
1008
1009 return savedPasswordExists() && (passwordEnabled ||
Danielle Millett58396982011-09-30 13:55:07 -04001010 (usingBiometricWeak() && backupEnabled));
Jim Miller69aa4a92009-12-22 19:03:28 -08001011 }
1012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -04001014 * @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 -08001015 */
1016 public boolean isLockPatternEnabled() {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001017 final boolean backupEnabled =
Jim Miller43120732014-04-14 16:56:08 -07001018 getLong(PASSWORD_TYPE_ALTERNATE_KEY,
1019 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)
1020 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
Danielle Millett73da5fe2011-09-13 16:20:05 -04001021
Jim Millera4edd152012-01-06 18:24:04 -08001022 return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
Jim Miller43120732014-04-14 16:56:08 -07001023 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)
Danielle Millett73da5fe2011-09-13 16:20:05 -04001024 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
Danielle Millett58396982011-09-30 13:55:07 -04001025 (usingBiometricWeak() && backupEnabled));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027
1028 /**
Danielle Millett58396982011-09-30 13:55:07 -04001029 * @return Whether biometric weak lock is installed and that the front facing camera exists
Jim Miller6edf2632011-09-05 16:03:14 -07001030 */
Danielle Millett58396982011-09-30 13:55:07 -04001031 public boolean isBiometricWeakInstalled() {
Danielle Millett58396982011-09-30 13:55:07 -04001032 // Check that it's installed
1033 PackageManager pm = mContext.getPackageManager();
1034 try {
1035 pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
1036 } catch (PackageManager.NameNotFoundException e) {
1037 return false;
1038 }
1039
1040 // Check that the camera is enabled
1041 if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
1042 return false;
1043 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001044 if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
Danielle Millett58396982011-09-30 13:55:07 -04001045 return false;
1046 }
1047
Brian Colonnaa0ee0042014-07-16 13:50:47 -04001048 // TODO: If we decide not to proceed with Face Unlock as a trustlet, this must be changed
1049 // back to returning true. If we become certain that Face Unlock will be a trustlet, this
1050 // entire function and a lot of other code can be removed.
1051 if (DEBUG) Log.d(TAG, "Forcing isBiometricWeakInstalled() to return false to disable it");
1052 return false;
Jim Miller6edf2632011-09-05 16:03:14 -07001053 }
1054
1055 /**
Danielle Millett925a7d82012-03-19 18:02:20 -04001056 * Set whether biometric weak liveliness is enabled.
1057 */
1058 public void setBiometricWeakLivelinessEnabled(boolean enabled) {
1059 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
1060 long newFlag;
1061 if (enabled) {
1062 newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
1063 } else {
1064 newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
1065 }
1066 setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
1067 }
1068
1069 /**
1070 * @return Whether the biometric weak liveliness is enabled.
1071 */
1072 public boolean isBiometricWeakLivelinessEnabled() {
1073 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
1074 return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
1075 }
1076
1077 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 * Set whether the lock pattern is enabled.
1079 */
1080 public void setLockPatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -08001081 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083
1084 /**
1085 * @return Whether the visible pattern is enabled.
1086 */
1087 public boolean isVisiblePatternEnabled() {
Jim Millera4edd152012-01-06 18:24:04 -08001088 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
1091 /**
1092 * Set whether the visible pattern is enabled.
1093 */
1094 public void setVisiblePatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -08001095 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001096
1097 // Update for crypto if owner
1098 int userId = getCurrentOrCallingUserId();
1099 if (userId != UserHandle.USER_OWNER) {
1100 return;
1101 }
1102
1103 IBinder service = ServiceManager.getService("mount");
1104 if (service == null) {
1105 Log.e(TAG, "Could not find the mount service to update the user info");
1106 return;
1107 }
1108
1109 IMountService mountService = IMountService.Stub.asInterface(service);
1110 try {
1111 mountService.setField("PatternVisible", enabled ? "1" : "0");
1112 } catch (RemoteException e) {
1113 Log.e(TAG, "Error changing pattern visible state", e);
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
1116
1117 /**
1118 * @return Whether tactile feedback for the pattern is enabled.
1119 */
1120 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001121 return Settings.System.getIntForUser(mContentResolver,
1122 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 }
1124
1125 /**
1126 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1127 * pattern until the deadline has passed.
1128 * @return the chosen deadline.
1129 */
1130 public long setLockoutAttemptDeadline() {
1131 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
1132 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
1133 return deadline;
1134 }
1135
1136 /**
1137 * @return The elapsed time in millis in the future when the user is allowed to
1138 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1139 * enter a pattern.
1140 */
1141 public long getLockoutAttemptDeadline() {
1142 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
1143 final long now = SystemClock.elapsedRealtime();
1144 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
1145 return 0L;
1146 }
1147 return deadline;
1148 }
1149
1150 /**
1151 * @return Whether the user is permanently locked out until they verify their
1152 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
1153 * attempts.
1154 */
1155 public boolean isPermanentlyLocked() {
Jim Millera4edd152012-01-06 18:24:04 -08001156 return getBoolean(LOCKOUT_PERMANENT_KEY, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 }
1158
1159 /**
1160 * Set the state of whether the device is permanently locked, meaning the user
Karl Rosaen678771b2009-08-21 14:00:26 -07001161 * must authenticate via other means.
1162 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 * @param locked Whether the user is permanently locked out until they verify their
1164 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
1165 * attempts.
1166 */
1167 public void setPermanentlyLocked(boolean locked) {
1168 setBoolean(LOCKOUT_PERMANENT_KEY, locked);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 }
1170
John Wang0f7b3f82011-05-31 11:20:55 -07001171 public boolean isEmergencyCallCapable() {
1172 return mContext.getResources().getBoolean(
1173 com.android.internal.R.bool.config_voice_capable);
1174 }
1175
1176 public boolean isPukUnlockScreenEnable() {
1177 return mContext.getResources().getBoolean(
1178 com.android.internal.R.bool.config_enable_puk_unlock_screen);
1179 }
1180
Jim Miller1f56edc2011-11-07 19:00:48 -08001181 public boolean isEmergencyCallEnabledWhileSimLocked() {
1182 return mContext.getResources().getBoolean(
1183 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
1184 }
1185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 /**
1187 * @return A formatted string of the next alarm (for showing on the lock screen),
1188 * or null if there is no next alarm.
1189 */
Jose Lima235510e2014-08-13 12:50:01 -07001190 public AlarmManager.AlarmClockInfo getNextAlarm() {
Adrian Roosedad7b22014-07-13 14:38:22 +02001191 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
1192 return alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194
Jim Millerf45bb402013-08-20 18:58:32 -07001195 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001196 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001197 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001198 } catch (RemoteException re) {
1199 return defaultValue;
1200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 }
1202
Jim Millerf45bb402013-08-20 18:58:32 -07001203 private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
1204 return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
1205 }
1206
1207 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001208 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001209 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001210 } catch (RemoteException re) {
1211 // What can we do?
1212 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 }
1215
Jim Millerf45bb402013-08-20 18:58:32 -07001216 private void setBoolean(String secureSettingKey, boolean enabled) {
1217 setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
1218 }
1219
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001220 public int[] getAppWidgets() {
Jim Millerf45bb402013-08-20 18:58:32 -07001221 return getAppWidgets(UserHandle.USER_CURRENT);
1222 }
1223
1224 private int[] getAppWidgets(int userId) {
Amith Yamasani8fd96ec2012-09-21 17:48:49 -07001225 String appWidgetIdString = Settings.Secure.getStringForUser(
Jim Millerf45bb402013-08-20 18:58:32 -07001226 mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001227 String delims = ",";
Michael Jurka1254f2f2012-10-25 11:44:31 -07001228 if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001229 String[] appWidgetStringIds = appWidgetIdString.split(delims);
1230 int[] appWidgetIds = new int[appWidgetStringIds.length];
1231 for (int i = 0; i < appWidgetStringIds.length; i++) {
1232 String appWidget = appWidgetStringIds[i];
1233 try {
1234 appWidgetIds[i] = Integer.decode(appWidget);
1235 } catch (NumberFormatException e) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001236 Log.d(TAG, "Error when parsing widget id " + appWidget);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001237 return null;
1238 }
1239 }
1240 return appWidgetIds;
Jim Millerf229e4d2012-09-12 20:32:50 -07001241 }
Michael Jurka67a871d2012-11-01 18:26:01 -07001242 return new int[0];
Jim Millerf229e4d2012-09-12 20:32:50 -07001243 }
1244
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001245 private static String combineStrings(int[] list, String separator) {
1246 int listLength = list.length;
1247
1248 switch (listLength) {
1249 case 0: {
1250 return "";
1251 }
1252 case 1: {
1253 return Integer.toString(list[0]);
1254 }
Michael Jurka20c41d52012-09-20 19:01:06 -07001255 }
1256
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001257 int strLength = 0;
1258 int separatorLength = separator.length();
1259
1260 String[] stringList = new String[list.length];
1261 for (int i = 0; i < listLength; i++) {
1262 stringList[i] = Integer.toString(list[i]);
1263 strLength += stringList[i].length();
1264 if (i < listLength - 1) {
1265 strLength += separatorLength;
1266 }
1267 }
1268
1269 StringBuilder sb = new StringBuilder(strLength);
1270
1271 for (int i = 0; i < listLength; i++) {
1272 sb.append(list[i]);
1273 if (i < listLength - 1) {
1274 sb.append(separator);
1275 }
1276 }
1277
1278 return sb.toString();
1279 }
1280
Jim Miller51117262012-11-04 17:58:09 -08001281 // appwidget used when appwidgets are disabled (we make an exception for
1282 // default clock widget)
1283 public void writeFallbackAppWidgetId(int appWidgetId) {
1284 Settings.Secure.putIntForUser(mContentResolver,
1285 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1286 appWidgetId,
1287 UserHandle.USER_CURRENT);
1288 }
1289
1290 // appwidget used when appwidgets are disabled (we make an exception for
1291 // default clock widget)
1292 public int getFallbackAppWidgetId() {
1293 return Settings.Secure.getIntForUser(
1294 mContentResolver,
1295 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1296 AppWidgetManager.INVALID_APPWIDGET_ID,
1297 UserHandle.USER_CURRENT);
1298 }
1299
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001300 private void writeAppWidgets(int[] appWidgetIds) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001301 Settings.Secure.putStringForUser(mContentResolver,
1302 Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
1303 combineStrings(appWidgetIds, ","),
1304 UserHandle.USER_CURRENT);
1305 }
1306
Michael Jurka1254f2f2012-10-25 11:44:31 -07001307 // TODO: log an error if this returns false
1308 public boolean addAppWidget(int widgetId, int index) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001309 int[] widgets = getAppWidgets();
Michael Jurka1254f2f2012-10-25 11:44:31 -07001310 if (widgets == null) {
1311 return false;
1312 }
Michael Jurka229dd8b2012-10-26 16:06:12 -07001313 if (index < 0 || index > widgets.length) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001314 return false;
1315 }
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001316 int[] newWidgets = new int[widgets.length + 1];
1317 for (int i = 0, j = 0; i < newWidgets.length; i++) {
1318 if (index == i) {
1319 newWidgets[i] = widgetId;
1320 i++;
1321 }
1322 if (i < newWidgets.length) {
1323 newWidgets[i] = widgets[j];
1324 j++;
1325 }
1326 }
1327 writeAppWidgets(newWidgets);
Michael Jurka1254f2f2012-10-25 11:44:31 -07001328 return true;
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001329 }
1330
Michael Jurka1254f2f2012-10-25 11:44:31 -07001331 public boolean removeAppWidget(int widgetId) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001332 int[] widgets = getAppWidgets();
Michael Jurka1254f2f2012-10-25 11:44:31 -07001333
Jim Millera9768602012-11-06 22:17:25 -08001334 if (widgets.length == 0) {
1335 return false;
1336 }
1337
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001338 int[] newWidgets = new int[widgets.length - 1];
1339 for (int i = 0, j = 0; i < widgets.length; i++) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001340 if (widgets[i] == widgetId) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001341 // continue...
Michael Jurka1254f2f2012-10-25 11:44:31 -07001342 } else if (j >= newWidgets.length) {
1343 // we couldn't find the widget
1344 return false;
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001345 } else {
1346 newWidgets[j] = widgets[i];
1347 j++;
1348 }
1349 }
1350 writeAppWidgets(newWidgets);
1351 return true;
Michael Jurka20c41d52012-09-20 19:01:06 -07001352 }
1353
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001354 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1355 try {
1356 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1357 } catch (RemoteException re) {
1358 return defaultValue;
1359 }
1360 }
1361
Amith Yamasani52c489c2012-03-28 11:42:42 -07001362 private long getLong(String secureSettingKey, long defaultValue) {
1363 try {
1364 return getLockSettings().getLong(secureSettingKey, defaultValue,
1365 getCurrentOrCallingUserId());
1366 } catch (RemoteException re) {
1367 return defaultValue;
1368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 }
1370
Amith Yamasani156c4352010-03-05 17:10:03 -08001371 private void setLong(String secureSettingKey, long value) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001372 setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1373 }
1374
1375 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001376 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001377 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001378 } catch (RemoteException re) {
1379 // What can we do?
1380 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001382 }
1383
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001384 private String getString(String secureSettingKey) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001385 return getString(secureSettingKey, getCurrentOrCallingUserId());
1386 }
1387
1388 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001389 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001390 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001391 } catch (RemoteException re) {
1392 return null;
1393 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001394 }
1395
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001396 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001397 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001398 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001399 } catch (RemoteException re) {
1400 // What can we do?
1401 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1402 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001403 }
1404
Jim Miller69aa4a92009-12-22 19:03:28 -08001405 public boolean isSecure() {
Jim Millercd709882010-03-25 18:24:02 -07001406 long mode = getKeyguardStoredPasswordQuality();
1407 final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1408 final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001409 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Jim Millercd709882010-03-25 18:24:02 -07001410 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001411 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1412 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Jim Millercd709882010-03-25 18:24:02 -07001413 final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
Danielle Millett73da5fe2011-09-13 16:20:05 -04001414 || isPassword && savedPasswordExists();
Jim Miller69aa4a92009-12-22 19:03:28 -08001415 return secure;
1416 }
Jim Miller69ac9882010-02-24 15:35:05 -08001417
1418 /**
John Wang0f7b3f82011-05-31 11:20:55 -07001419 * Sets the emergency button visibility based on isEmergencyCallCapable().
1420 *
1421 * If the emergency button is visible, sets the text on the emergency button
1422 * to indicate what action will be taken.
1423 *
Jim Miller69ac9882010-02-24 15:35:05 -08001424 * If there's currently a call in progress, the button will take them to the call
Santos Cordon0bae09f2014-07-07 14:53:10 -07001425 * @param button The button to update
1426 * @param shown Indicates whether the given screen wants the emergency button to show at all
1427 * @param showIcon Indicates whether to show a phone icon for the button.
Jim Miller69ac9882010-02-24 15:35:05 -08001428 */
Santos Cordon0bae09f2014-07-07 14:53:10 -07001429 public void updateEmergencyCallButtonState(Button button, boolean shown, boolean showIcon) {
Jim Miller1f56edc2011-11-07 19:00:48 -08001430 if (isEmergencyCallCapable() && shown) {
John Wang0f7b3f82011-05-31 11:20:55 -07001431 button.setVisibility(View.VISIBLE);
1432 } else {
1433 button.setVisibility(View.GONE);
1434 return;
1435 }
1436
Jim Miller69ac9882010-02-24 15:35:05 -08001437 int textId;
Santos Cordon0bae09f2014-07-07 14:53:10 -07001438 if (getPhoneManager().isInAPhoneCall()) {
Jim Miller69ac9882010-02-24 15:35:05 -08001439 // show "return to call" text and show phone icon
1440 textId = R.string.lockscreen_return_to_call;
Jim Miller109f1fd2012-09-19 20:44:16 -07001441 int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
Jim Miller69ac9882010-02-24 15:35:05 -08001442 button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
1443 } else {
1444 textId = R.string.lockscreen_emergency_call;
Jim Miller109f1fd2012-09-19 20:44:16 -07001445 int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
Jim Miller69ac9882010-02-24 15:35:05 -08001446 button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
1447 }
Jim Millere38c8e22013-09-24 15:54:04 -07001448 button.setText(textId);
Jim Miller69ac9882010-02-24 15:35:05 -08001449 }
1450
1451 /**
1452 * Resumes a call in progress. Typically launched from the EmergencyCall button
1453 * on various lockscreens.
Jim Miller69ac9882010-02-24 15:35:05 -08001454 */
Santos Cordon3534ede2014-05-29 13:07:10 -07001455 public void resumeCall() {
Santos Cordon0bae09f2014-07-07 14:53:10 -07001456 getPhoneManager().showCallScreen(false);
1457 }
1458
1459 private PhoneManager getPhoneManager() {
1460 return (PhoneManager) mContext.getSystemService(Context.PHONE_SERVICE);
Jim Miller69ac9882010-02-24 15:35:05 -08001461 }
Danielle Millett044a0a72011-11-07 15:42:12 -05001462
1463 private void finishBiometricWeak() {
1464 setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
1465
1466 // Launch intent to show final screen, this also
1467 // moves the temporary gallery to the actual gallery
1468 Intent intent = new Intent();
1469 intent.setClassName("com.android.facelock",
1470 "com.android.facelock.SetupEndScreen");
1471 mContext.startActivity(intent);
1472 }
1473
Jim Millera4edd152012-01-06 18:24:04 -08001474 public void setPowerButtonInstantlyLocks(boolean enabled) {
1475 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
1476 }
1477
1478 public boolean getPowerButtonInstantlyLocks() {
1479 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
1480 }
Jim Millera9768602012-11-06 22:17:25 -08001481
Jim Miller51117262012-11-04 17:58:09 -08001482 public static boolean isSafeModeEnabled() {
1483 try {
1484 return IWindowManager.Stub.asInterface(
1485 ServiceManager.getService("window")).isSafeModeEnabled();
1486 } catch (RemoteException e) {
1487 // Shouldn't happen!
1488 }
1489 return false;
1490 }
Jim Millera4edd152012-01-06 18:24:04 -08001491
Jim Millerf45bb402013-08-20 18:58:32 -07001492 /**
1493 * Determine whether the user has selected any non-system widgets in keyguard
1494 *
1495 * @return true if widgets have been selected
1496 */
1497 public boolean hasWidgetsEnabledInKeyguard(int userid) {
1498 int widgets[] = getAppWidgets(userid);
1499 for (int i = 0; i < widgets.length; i++) {
1500 if (widgets[i] > 0) {
1501 return true;
1502 }
1503 }
1504 return false;
1505 }
1506
1507 public boolean getWidgetsEnabled() {
1508 return getWidgetsEnabled(getCurrentOrCallingUserId());
1509 }
1510
1511 public boolean getWidgetsEnabled(int userId) {
1512 return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
1513 }
1514
1515 public void setWidgetsEnabled(boolean enabled) {
1516 setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
1517 }
1518
1519 public void setWidgetsEnabled(boolean enabled, int userId) {
1520 setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
1521 }
1522
Adrian Roos82142c22014-03-27 14:56:59 +01001523 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
1524 setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
1525 }
1526
1527 public List<ComponentName> getEnabledTrustAgents() {
1528 return getEnabledTrustAgents(getCurrentOrCallingUserId());
1529 }
1530
1531 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1532 StringBuilder sb = new StringBuilder();
1533 for (ComponentName cn : activeTrustAgents) {
1534 if (sb.length() > 0) {
1535 sb.append(',');
1536 }
1537 sb.append(cn.flattenToShortString());
1538 }
1539 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
1540 getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
1541 }
1542
1543 public List<ComponentName> getEnabledTrustAgents(int userId) {
1544 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1545 if (TextUtils.isEmpty(serialized)) {
1546 return null;
1547 }
1548 String[] split = serialized.split(",");
1549 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1550 for (String s : split) {
1551 if (!TextUtils.isEmpty(s)) {
1552 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1553 }
1554 }
1555 return activeTrustAgents;
1556 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001557
1558 /**
1559 * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
1560 */
1561 public void requireCredentialEntry(int userId) {
1562 getTrustManager().reportRequireCredentialEntry(userId);
1563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564}