blob: 860226047d3cc680e99ec2cc08bcb488d975e9ba [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.widget;
18
Jim Miller78c48f62013-03-01 15:28:33 -080019import android.Manifest;
Amith Yamasani4b4b9542012-09-14 13:36:29 -070020import android.app.ActivityManagerNative;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080021import android.app.admin.DevicePolicyManager;
Jim Miller51117262012-11-04 17:58:09 -080022import android.appwidget.AppWidgetManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080024import android.content.Context;
Steven Ross329979c2011-09-28 11:42:56 -040025import android.content.Intent;
Danielle Millett58396982011-09-30 13:55:07 -040026import android.content.pm.PackageManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -070027import android.os.Binder;
Jason parksf7b3cd42011-01-27 09:28:25 -060028import android.os.IBinder;
Jim Miller69ac9882010-02-24 15:35:05 -080029import android.os.RemoteException;
30import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070032import android.os.UserHandle;
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;
Jim Miller69ac9882010-02-24 15:35:05 -080035import android.telephony.TelephonyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.text.TextUtils;
37import android.util.Log;
Jim Miller51117262012-11-04 17:58:09 -080038import android.view.IWindowManager;
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
Michael Jurka1254f2f2012-10-25 11:44:31 -070042import com.android.internal.R;
43import com.android.internal.telephony.ITelephony;
44import com.google.android.collect.Lists;
Michael Jurkaaa2859a2012-10-24 12:46:49 -070045
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.List;
50
51/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070052 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 */
54public class LockPatternUtils {
55
56 private static final String TAG = "LockPatternUtils";
Jim Miller69aa4a92009-12-22 19:03:28 -080057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 /**
59 * The maximum number of incorrect attempts before the user is prevented
60 * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
61 */
62 public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
63
64 /**
65 * The number of incorrect attempts before which we fall back on an alternative
66 * method of verifying the user, and resetting their lock pattern.
67 */
68 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
69
70 /**
71 * How long the user is prevented from trying again after entering the
72 * wrong pattern too many times.
73 */
74 public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
75
76 /**
77 * The interval of the countdown for showing progress of the lockout.
78 */
79 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
80
Jim Miller4f369952011-08-19 18:29:22 -070081
82 /**
83 * This dictates when we start telling the user that continued failed attempts will wipe
84 * their device.
85 */
86 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
87
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 /**
89 * The minimum number of dots in a valid pattern.
90 */
91 public static final int MIN_LOCK_PATTERN_SIZE = 4;
92
93 /**
94 * The minimum number of dots the user must include in a wrong pattern
95 * attempt for it to be counted against the counts that affect
96 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
97 */
Jim Miller4f369952011-08-19 18:29:22 -070098 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Danielle Millett925a7d82012-03-19 18:02:20 -0400100 /**
Adam Cohenf7522022012-10-03 20:03:18 -0700101 * Tells the keyguard to show the user switcher when the keyguard is created.
102 */
103 public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
104
105 /**
106 * Tells the keyguard to show the security challenge when the keyguard is created.
107 */
108 public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
109
110 /**
Michael Jurka76017ca2012-11-06 16:21:09 -0800111 * Tells the keyguard to show the widget with the specified id when the keyguard is created.
112 */
113 public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
114
115 /**
Danielle Millett925a7d82012-03-19 18:02:20 -0400116 * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
117 * be used
118 */
119 public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
120
Michael Jurka1254f2f2012-10-25 11:44:31 -0700121 /**
122 * Pseudo-appwidget id we use to represent the default clock status widget
123 */
124 public static final int ID_DEFAULT_STATUS_WIDGET = -2;
125
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800126 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
127 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
128 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800129 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Jim Miller6edf2632011-09-05 16:03:14 -0700130 public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800131 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
132 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
133 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Jim Miller6edf2632011-09-05 16:03:14 -0700134 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
135 = "lockscreen.biometric_weak_fallback";
Danielle Millett7a072192011-10-03 17:36:01 -0400136 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
137 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800138 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
139 = "lockscreen.power_button_instantly_locks";
Jim Millerf45bb402013-08-20 18:58:32 -0700140 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800142 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700143
Jim Miller187ec582013-04-15 18:27:54 -0700144 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
145 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
146 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
147
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800148 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800150 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700151 private ILockSettings mLockSettingsService;
Jim Milleree82f8f2012-10-01 16:26:18 -0700152
Jim Miller78c48f62013-03-01 15:28:33 -0800153 private final boolean mMultiUserMode;
154
Jim Milleree82f8f2012-10-01 16:26:18 -0700155 // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
156 private static volatile int sCurrentUserId = UserHandle.USER_NULL;
Dianne Hackbornde4c26f2011-07-17 13:42:47 -0700157
Jim Millercd709882010-03-25 18:24:02 -0700158 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800159 if (mDevicePolicyManager == null) {
160 mDevicePolicyManager =
161 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
162 if (mDevicePolicyManager == null) {
163 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
164 new IllegalStateException("Stack trace:"));
165 }
166 }
167 return mDevicePolicyManager;
168 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 /**
171 * @param contentResolver Used to look up and save settings.
172 */
Jim Miller31f90b62010-01-20 13:35:20 -0800173 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800174 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800175 mContentResolver = context.getContentResolver();
Jim Miller78c48f62013-03-01 15:28:33 -0800176
177 // If this is being called by the system or by an application like keyguard that
178 // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
179 // mode where calls are for the current user rather than the user of the calling process.
180 mMultiUserMode = context.checkCallingOrSelfPermission(
181 Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700182 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800183
Amith Yamasani52c489c2012-03-28 11:42:42 -0700184 private ILockSettings getLockSettings() {
185 if (mLockSettingsService == null) {
186 mLockSettingsService = ILockSettings.Stub.asInterface(
187 (IBinder) ServiceManager.getService("lock_settings"));
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700188 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700189 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 }
191
Jim Miller31f90b62010-01-20 13:35:20 -0800192 public int getRequestedMinimumPasswordLength() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700193 return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800194 }
195
Jim Miller31f90b62010-01-20 13:35:20 -0800196 /**
197 * Gets the device policy password mode. If the mode is non-specific, returns
198 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800199 */
Jim Millercd709882010-03-25 18:24:02 -0700200 public int getRequestedPasswordQuality() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700201 return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800202 }
203
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700204 public int getRequestedPasswordHistoryLength() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700205 return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700206 }
207
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700208 public int getRequestedPasswordMinimumLetters() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700209 return getDevicePolicyManager().getPasswordMinimumLetters(null,
210 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700211 }
212
213 public int getRequestedPasswordMinimumUpperCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700214 return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
215 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700216 }
217
218 public int getRequestedPasswordMinimumLowerCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700219 return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
220 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700221 }
222
223 public int getRequestedPasswordMinimumNumeric() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700224 return getDevicePolicyManager().getPasswordMinimumNumeric(null,
225 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700226 }
227
228 public int getRequestedPasswordMinimumSymbols() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700229 return getDevicePolicyManager().getPasswordMinimumSymbols(null,
230 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700231 }
232
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700233 public int getRequestedPasswordMinimumNonLetter() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700234 return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
235 getCurrentOrCallingUserId());
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700236 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700237
Jim Miller31f90b62010-01-20 13:35:20 -0800238 /**
239 * Returns the actual password mode, as set by keyguard after updating the password.
240 *
241 * @return
242 */
Jim Miller31f90b62010-01-20 13:35:20 -0800243 public void reportFailedPasswordAttempt() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700244 getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800245 }
246
247 public void reportSuccessfulPasswordAttempt() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700248 getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800249 }
250
Amith Yamasani52c489c2012-03-28 11:42:42 -0700251 public void setCurrentUser(int userId) {
Jim Milleree82f8f2012-10-01 16:26:18 -0700252 sCurrentUserId = userId;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700253 }
254
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700255 public int getCurrentUser() {
Jim Milleree82f8f2012-10-01 16:26:18 -0700256 if (sCurrentUserId != UserHandle.USER_NULL) {
Jim Miller25645d82012-09-21 14:47:54 -0700257 // Someone is regularly updating using setCurrentUser() use that value.
Jim Milleree82f8f2012-10-01 16:26:18 -0700258 return sCurrentUserId;
Jim Miller25645d82012-09-21 14:47:54 -0700259 }
260 try {
261 return ActivityManagerNative.getDefault().getCurrentUser().id;
262 } catch (RemoteException re) {
263 return UserHandle.USER_OWNER;
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700264 }
265 }
266
Amith Yamasani52c489c2012-03-28 11:42:42 -0700267 public void removeUser(int userId) {
Jim Miller25645d82012-09-21 14:47:54 -0700268 try {
269 getLockSettings().removeUser(userId);
270 } catch (RemoteException re) {
271 Log.e(TAG, "Couldn't remove lock settings for user " + userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700272 }
273 }
274
275 private int getCurrentOrCallingUserId() {
Jim Miller78c48f62013-03-01 15:28:33 -0800276 if (mMultiUserMode) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700277 // TODO: This is a little inefficient. See if all users of this are able to
278 // handle USER_CURRENT and pass that instead.
279 return getCurrentUser();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700280 } else {
Jim Miller78c48f62013-03-01 15:28:33 -0800281 return UserHandle.getCallingUserId();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700282 }
283 }
284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 /**
286 * Check to see if a pattern matches the saved pattern. If no pattern exists,
287 * always returns true.
288 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800289 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 */
291 public boolean checkPattern(List<LockPatternView.Cell> pattern) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700292 final int userId = getCurrentOrCallingUserId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 try {
Jim Millerde1af082013-09-11 14:58:26 -0700294 return getLockSettings().checkPattern(patternToString(pattern), userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700295 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 return true;
297 }
298 }
299
300 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800301 * Check to see if a password matches the saved password. If no password exists,
302 * always returns true.
303 * @param password The password to check.
304 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800306 public boolean checkPassword(String password) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700307 final int userId = getCurrentOrCallingUserId();
Jim Miller69aa4a92009-12-22 19:03:28 -0800308 try {
Jim Millerde1af082013-09-11 14:58:26 -0700309 return getLockSettings().checkPassword(password, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700310 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800311 return true;
312 }
313 }
314
315 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700316 * Check to see if a password matches any of the passwords stored in the
317 * password history.
318 *
319 * @param password The password to check.
320 * @return Whether the password matches any in the history.
321 */
322 public boolean checkPasswordHistory(String password) {
323 String passwordHashString = new String(passwordToHash(password));
324 String passwordHistory = getString(PASSWORD_HISTORY_KEY);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700325 if (passwordHistory == null) {
326 return false;
327 }
328 // Password History may be too long...
329 int passwordHashLength = passwordHashString.length();
330 int passwordHistoryLength = getRequestedPasswordHistoryLength();
331 if(passwordHistoryLength == 0) {
332 return false;
333 }
334 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
335 + passwordHistoryLength - 1;
336 if (passwordHistory.length() > neededPasswordHistoryLength) {
337 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
338 }
339 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700340 }
341
342 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800343 * Check to see if the user has stored a lock pattern.
344 * @return Whether a saved pattern exists.
345 */
346 public boolean savedPatternExists() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700347 try {
348 return getLockSettings().havePattern(getCurrentOrCallingUserId());
349 } catch (RemoteException re) {
350 return false;
351 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800352 }
353
354 /**
355 * Check to see if the user has stored a lock pattern.
356 * @return Whether a saved pattern exists.
357 */
358 public boolean savedPasswordExists() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700359 try {
360 return getLockSettings().havePassword(getCurrentOrCallingUserId());
361 } catch (RemoteException re) {
362 return false;
363 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800364 }
365
366 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700367 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
368 * currently cleared.
369 *
370 * @return True if the user has ever chosen a pattern.
371 */
372 public boolean isPatternEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800373 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700374 }
375
376 /**
Danielle Millett7a072192011-10-03 17:36:01 -0400377 * Return true if the user has ever chosen biometric weak. This is true even if biometric
378 * weak is not current set.
379 *
380 * @return True if the user has ever chosen biometric weak.
381 */
382 public boolean isBiometricWeakEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800383 return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
Danielle Millett7a072192011-10-03 17:36:01 -0400384 }
385
386 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700387 * Used by device policy manager to validate the current password
388 * information it has.
389 */
390 public int getActivePasswordQuality() {
Jim Millercd709882010-03-25 18:24:02 -0700391 int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400392 // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
393 // return biometric_weak if that is being used instead of the backup
394 int quality =
395 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
396 switch (quality) {
Jim Millercd709882010-03-25 18:24:02 -0700397 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700398 if (isLockPatternEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700399 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700400 }
Jim Millercd709882010-03-25 18:24:02 -0700401 break;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400402 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
403 if (isBiometricWeakInstalled()) {
404 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
405 }
406 break;
Jim Millercd709882010-03-25 18:24:02 -0700407 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700408 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700409 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700410 }
Jim Millercd709882010-03-25 18:24:02 -0700411 break;
412 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700413 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700414 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700415 }
Jim Millercd709882010-03-25 18:24:02 -0700416 break;
417 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
418 if (isLockPasswordEnabled()) {
419 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
420 }
421 break;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700422 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
423 if (isLockPasswordEnabled()) {
424 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
425 }
426 break;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700427 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400428
Jim Millercd709882010-03-25 18:24:02 -0700429 return activePasswordQuality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700430 }
Jim Millercd709882010-03-25 18:24:02 -0700431
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700432 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800433 * Clear any lock pattern or password.
434 */
Steven Ross329979c2011-09-28 11:42:56 -0400435 public void clearLock(boolean isFallback) {
436 if(!isFallback) deleteGallery();
Jim Millercd709882010-03-25 18:24:02 -0700437 saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800438 setLockPatternEnabled(false);
439 saveLockPattern(null);
Jim Miller93708af12012-01-25 18:26:12 -0800440 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700441 setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800442 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800443
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800444 /**
Jim Miller2a98a4c2010-11-19 18:49:26 -0800445 * Disable showing lock screen at all when the DevicePolicyManager allows it.
446 * This is only meaningful if pattern, pin or password are not set.
447 *
448 * @param disable Disables lock screen when true
449 */
450 public void setLockScreenDisabled(boolean disable) {
451 setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
452 }
453
454 /**
455 * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
456 * show LockScreen or go straight to the home screen.
457 *
458 * @return true if lock screen is can be disabled
459 */
460 public boolean isLockScreenDisabled() {
461 return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
462 }
463
464 /**
Steven Ross3553c292011-09-30 15:48:40 -0400465 * Calls back SetupFaceLock to delete the temporary gallery file
Steven Ross329979c2011-09-28 11:42:56 -0400466 */
467 public void deleteTempGallery() {
Danielle Millett574e49e2012-03-27 16:17:10 -0400468 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
Steven Ross3553c292011-09-30 15:48:40 -0400469 intent.putExtra("deleteTempGallery", true);
Danielle Millett574e49e2012-03-27 16:17:10 -0400470 mContext.sendBroadcast(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400471 }
472
473 /**
474 * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
475 */
476 void deleteGallery() {
Danielle Millett58396982011-09-30 13:55:07 -0400477 if(usingBiometricWeak()) {
Danielle Millett574e49e2012-03-27 16:17:10 -0400478 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
Steven Ross329979c2011-09-28 11:42:56 -0400479 intent.putExtra("deleteGallery", true);
Danielle Millett574e49e2012-03-27 16:17:10 -0400480 mContext.sendBroadcast(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400481 }
482 }
483
484 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700485 * Save a lock pattern.
486 * @param pattern The new pattern to save.
Danielle Millett2364a222011-12-21 17:02:32 -0500487 */
488 public void saveLockPattern(List<LockPatternView.Cell> pattern) {
489 this.saveLockPattern(pattern, false);
490 }
491
492 /**
493 * Save a lock pattern.
494 * @param pattern The new pattern to save.
Jim Miller6edf2632011-09-05 16:03:14 -0700495 * @param isFallback Specifies if this is a fallback to biometric weak
496 */
497 public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 try {
Jim Millerde1af082013-09-11 14:58:26 -0700499 getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800500 DevicePolicyManager dpm = getDevicePolicyManager();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800501 if (pattern != null) {
502 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
Jim Miller6edf2632011-09-05 16:03:14 -0700503 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400504 deleteGallery();
Jim Miller6edf2632011-09-05 16:03:14 -0700505 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett2364a222011-12-21 17:02:32 -0500506 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700507 pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700508 } else {
509 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
510 setLong(PASSWORD_TYPE_ALTERNATE_KEY,
511 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett044a0a72011-11-07 15:42:12 -0500512 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500513 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700514 0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700515 }
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800516 } else {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700517 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700518 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800519 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700520 } catch (RemoteException re) {
521 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
523 }
524
Jim Miller187ec582013-04-15 18:27:54 -0700525 public void setOwnerInfo(String info, int userId) {
526 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
527 }
528
529 public void setOwnerInfoEnabled(boolean enabled) {
530 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
531 }
532
533 public String getOwnerInfo(int userId) {
534 return getString(LOCK_SCREEN_OWNER_INFO);
535 }
536
537 public boolean isOwnerInfoEnabled() {
538 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
539 }
540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700542 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800543 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700544 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800545 boolean hasDigit = false;
546 boolean hasNonDigit = false;
547 final int len = password.length();
548 for (int i = 0; i < len; i++) {
549 if (Character.isDigit(password.charAt(i))) {
550 hasDigit = true;
551 } else {
552 hasNonDigit = true;
553 }
554 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800555
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700556 if (hasNonDigit && hasDigit) {
557 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800558 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800559 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700560 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800561 }
562 if (hasDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700563 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800564 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700565 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800566 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800567
Jason parksf7b3cd42011-01-27 09:28:25 -0600568 /** Update the encryption password if it is enabled **/
569 private void updateEncryptionPassword(String password) {
570 DevicePolicyManager dpm = getDevicePolicyManager();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700571 if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
572 != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600573 return;
574 }
575
576 IBinder service = ServiceManager.getService("mount");
577 if (service == null) {
578 Log.e(TAG, "Could not find the mount service to update the encryption password");
579 return;
580 }
581
582 IMountService mountService = IMountService.Stub.asInterface(service);
583 try {
584 mountService.changeEncryptionPassword(password);
585 } catch (RemoteException e) {
586 Log.e(TAG, "Error changing encryption password", e);
587 }
588 }
589
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800590 /**
Jim Millercd709882010-03-25 18:24:02 -0700591 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800592 * as the requested mode, but will adjust the mode to be as good as the
593 * pattern.
Jim Miller69aa4a92009-12-22 19:03:28 -0800594 * @param password The password to save
Jim Millercd709882010-03-25 18:24:02 -0700595 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Jim Miller69aa4a92009-12-22 19:03:28 -0800596 */
Jim Millercd709882010-03-25 18:24:02 -0700597 public void saveLockPassword(String password, int quality) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700598 this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700599 }
600
601 /**
602 * Save a lock password. Does not ensure that the password is as good
603 * as the requested mode, but will adjust the mode to be as good as the
604 * pattern.
605 * @param password The password to save
606 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
607 * @param isFallback Specifies if this is a fallback to biometric weak
608 */
609 public void saveLockPassword(String password, int quality, boolean isFallback) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700610 saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
611 }
612
613 /**
614 * Save a lock password. Does not ensure that the password is as good
615 * as the requested mode, but will adjust the mode to be as good as the
616 * pattern.
617 * @param password The password to save
618 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
619 * @param isFallback Specifies if this is a fallback to biometric weak
620 * @param userHandle The userId of the user to change the password for
621 */
622 public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800623 try {
Jim Millerde1af082013-09-11 14:58:26 -0700624 getLockSettings().setLockPassword(password, userHandle);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800625 DevicePolicyManager dpm = getDevicePolicyManager();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800626 if (password != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700627 if (userHandle == UserHandle.USER_OWNER) {
628 // Update the encryption password.
629 updateEncryptionPassword(password);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700630 }
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700631
Jim Millercd709882010-03-25 18:24:02 -0700632 int computedQuality = computePasswordQuality(password);
Jim Miller6edf2632011-09-05 16:03:14 -0700633 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400634 deleteGallery();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700635 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500636 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
637 int letters = 0;
638 int uppercase = 0;
639 int lowercase = 0;
640 int numbers = 0;
641 int symbols = 0;
642 int nonletter = 0;
643 for (int i = 0; i < password.length(); i++) {
644 char c = password.charAt(i);
645 if (c >= 'A' && c <= 'Z') {
646 letters++;
647 uppercase++;
648 } else if (c >= 'a' && c <= 'z') {
649 letters++;
650 lowercase++;
651 } else if (c >= '0' && c <= '9') {
652 numbers++;
653 nonletter++;
654 } else {
655 symbols++;
656 nonletter++;
657 }
658 }
659 dpm.setActivePasswordState(Math.max(quality, computedQuality),
660 password.length(), letters, uppercase, lowercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700661 numbers, symbols, nonletter, userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500662 } else {
663 // The password is not anything.
664 dpm.setActivePasswordState(
665 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700666 0, 0, 0, 0, 0, 0, 0, userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500667 }
Jim Miller6edf2632011-09-05 16:03:14 -0700668 } else {
Danielle Millett2364a222011-12-21 17:02:32 -0500669 // Case where it's a fallback for biometric weak
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700670 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
671 userHandle);
672 setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
673 userHandle);
Danielle Millett044a0a72011-11-07 15:42:12 -0500674 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500675 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700676 0, 0, 0, 0, 0, 0, 0, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700677 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700678 // Add the password to the password history. We assume all
679 // password
680 // hashes have the same length for simplicity of implementation.
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700681 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700682 if (passwordHistory == null) {
683 passwordHistory = new String();
684 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700685 int passwordHistoryLength = getRequestedPasswordHistoryLength();
686 if (passwordHistoryLength == 0) {
687 passwordHistory = "";
688 } else {
Jim Millerde1af082013-09-11 14:58:26 -0700689 byte[] hash = passwordToHash(password);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700690 passwordHistory = new String(hash) + "," + passwordHistory;
691 // Cut it to contain passwordHistoryLength hashes
692 // and passwordHistoryLength -1 commas.
693 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
694 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
695 .length()));
696 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700697 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800698 } else {
699 dpm.setActivePasswordState(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700700 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
701 userHandle);
Jim Miller31f90b62010-01-20 13:35:20 -0800702 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700703 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800704 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700705 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800706 }
707 }
708
Jim Millercd709882010-03-25 18:24:02 -0700709 /**
710 * Retrieves the quality mode we're in.
711 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
712 *
713 * @return stored password quality
714 */
715 public int getKeyguardStoredPasswordQuality() {
Jim Miller6edf2632011-09-05 16:03:14 -0700716 int quality =
717 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
718 // If the user has chosen to use weak biometric sensor, then return the backup locking
719 // method and treat biometric as a special case.
720 if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
721 quality =
722 (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
723 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
724 }
725 return quality;
726 }
727
Danielle Millett58396982011-09-30 13:55:07 -0400728 /**
729 * @return true if the lockscreen method is set to biometric weak
730 */
Jim Miller6edf2632011-09-05 16:03:14 -0700731 public boolean usingBiometricWeak() {
732 int quality =
733 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
734 return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
Jim Miller69aa4a92009-12-22 19:03:28 -0800735 }
736
737 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 * Deserialize a pattern.
739 * @param string The pattern serialized with {@link #patternToString}
740 * @return The pattern.
741 */
742 public static List<LockPatternView.Cell> stringToPattern(String string) {
743 List<LockPatternView.Cell> result = Lists.newArrayList();
744
745 final byte[] bytes = string.getBytes();
746 for (int i = 0; i < bytes.length; i++) {
747 byte b = bytes[i];
748 result.add(LockPatternView.Cell.of(b / 3, b % 3));
749 }
750 return result;
751 }
752
753 /**
754 * Serialize a pattern.
755 * @param pattern The pattern.
756 * @return The pattern in string form.
757 */
758 public static String patternToString(List<LockPatternView.Cell> pattern) {
759 if (pattern == null) {
760 return "";
761 }
762 final int patternSize = pattern.size();
763
764 byte[] res = new byte[patternSize];
765 for (int i = 0; i < patternSize; i++) {
766 LockPatternView.Cell cell = pattern.get(i);
767 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
768 }
769 return new String(res);
770 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 /*
773 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
774 * at least a second level of protection. First level is that the file
775 * is in a location only readable by the system process.
776 * @param pattern the gesture pattern.
777 * @return the hash of the pattern in a byte array.
778 */
Jim Millerde1af082013-09-11 14:58:26 -0700779 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 if (pattern == null) {
781 return null;
782 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 final int patternSize = pattern.size();
785 byte[] res = new byte[patternSize];
786 for (int i = 0; i < patternSize; i++) {
787 LockPatternView.Cell cell = pattern.get(i);
788 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
789 }
790 try {
791 MessageDigest md = MessageDigest.getInstance("SHA-1");
792 byte[] hash = md.digest(res);
793 return hash;
794 } catch (NoSuchAlgorithmException nsa) {
795 return res;
796 }
797 }
798
Jim Miller11b019d2010-01-20 16:34:45 -0800799 private String getSalt() {
800 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
801 if (salt == 0) {
802 try {
803 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
804 setLong(LOCK_PASSWORD_SALT_KEY, salt);
805 Log.v(TAG, "Initialized lock password salt");
806 } catch (NoSuchAlgorithmException e) {
807 // Throw an exception rather than storing a password we'll never be able to recover
808 throw new IllegalStateException("Couldn't get SecureRandom number", e);
809 }
810 }
811 return Long.toHexString(salt);
812 }
813
Jim Miller69aa4a92009-12-22 19:03:28 -0800814 /*
815 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
816 * Not the most secure, but it is at least a second level of protection. First level is that
817 * the file is in a location only readable by the system process.
818 * @param password the gesture pattern.
819 * @return the hash of the pattern in a byte array.
820 */
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700821 public byte[] passwordToHash(String password) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800822 if (password == null) {
823 return null;
824 }
825 String algo = null;
826 byte[] hashed = null;
827 try {
Jim Miller11b019d2010-01-20 16:34:45 -0800828 byte[] saltedPassword = (password + getSalt()).getBytes();
Jim Miller69aa4a92009-12-22 19:03:28 -0800829 byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
830 byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
831 hashed = (toHex(sha1) + toHex(md5)).getBytes();
832 } catch (NoSuchAlgorithmException e) {
833 Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
834 }
835 return hashed;
836 }
837
838 private static String toHex(byte[] ary) {
839 final String hex = "0123456789ABCDEF";
840 String ret = "";
841 for (int i = 0; i < ary.length; i++) {
842 ret += hex.charAt((ary[i] >> 4) & 0xf);
843 ret += hex.charAt(ary[i] & 0xf);
844 }
845 return ret;
846 }
847
848 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400849 * @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 -0800850 */
851 public boolean isLockPasswordEnabled() {
852 long mode = getLong(PASSWORD_TYPE_KEY, 0);
Danielle Millett73da5fe2011-09-13 16:20:05 -0400853 long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
854 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
855 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
856 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
857 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
858 final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
859 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
860 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
861 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
862
863 return savedPasswordExists() && (passwordEnabled ||
Danielle Millett58396982011-09-30 13:55:07 -0400864 (usingBiometricWeak() && backupEnabled));
Jim Miller69aa4a92009-12-22 19:03:28 -0800865 }
866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400868 * @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 -0800869 */
870 public boolean isLockPatternEnabled() {
Danielle Millett73da5fe2011-09-13 16:20:05 -0400871 final boolean backupEnabled =
872 getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
873 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
874
Jim Millera4edd152012-01-06 18:24:04 -0800875 return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
Danielle Millett73da5fe2011-09-13 16:20:05 -0400876 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
877 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
Danielle Millett58396982011-09-30 13:55:07 -0400878 (usingBiometricWeak() && backupEnabled));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
880
881 /**
Danielle Millett58396982011-09-30 13:55:07 -0400882 * @return Whether biometric weak lock is installed and that the front facing camera exists
Jim Miller6edf2632011-09-05 16:03:14 -0700883 */
Danielle Millett58396982011-09-30 13:55:07 -0400884 public boolean isBiometricWeakInstalled() {
Danielle Millett58396982011-09-30 13:55:07 -0400885 // Check that it's installed
886 PackageManager pm = mContext.getPackageManager();
887 try {
888 pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
889 } catch (PackageManager.NameNotFoundException e) {
890 return false;
891 }
892
893 // Check that the camera is enabled
894 if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
895 return false;
896 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700897 if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
Danielle Millett58396982011-09-30 13:55:07 -0400898 return false;
899 }
900
901
902 return true;
Jim Miller6edf2632011-09-05 16:03:14 -0700903 }
904
905 /**
Danielle Millett925a7d82012-03-19 18:02:20 -0400906 * Set whether biometric weak liveliness is enabled.
907 */
908 public void setBiometricWeakLivelinessEnabled(boolean enabled) {
909 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
910 long newFlag;
911 if (enabled) {
912 newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
913 } else {
914 newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
915 }
916 setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
917 }
918
919 /**
920 * @return Whether the biometric weak liveliness is enabled.
921 */
922 public boolean isBiometricWeakLivelinessEnabled() {
923 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
924 return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
925 }
926
927 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 * Set whether the lock pattern is enabled.
929 */
930 public void setLockPatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800931 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 }
933
934 /**
935 * @return Whether the visible pattern is enabled.
936 */
937 public boolean isVisiblePatternEnabled() {
Jim Millera4edd152012-01-06 18:24:04 -0800938 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 }
940
941 /**
942 * Set whether the visible pattern is enabled.
943 */
944 public void setVisiblePatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800945 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 }
947
948 /**
949 * @return Whether tactile feedback for the pattern is enabled.
950 */
951 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -0700952 return Settings.System.getIntForUser(mContentResolver,
953 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
955
956 /**
957 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
958 * pattern until the deadline has passed.
959 * @return the chosen deadline.
960 */
961 public long setLockoutAttemptDeadline() {
962 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
963 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
964 return deadline;
965 }
966
967 /**
968 * @return The elapsed time in millis in the future when the user is allowed to
969 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
970 * enter a pattern.
971 */
972 public long getLockoutAttemptDeadline() {
973 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
974 final long now = SystemClock.elapsedRealtime();
975 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
976 return 0L;
977 }
978 return deadline;
979 }
980
981 /**
982 * @return Whether the user is permanently locked out until they verify their
983 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
984 * attempts.
985 */
986 public boolean isPermanentlyLocked() {
Jim Millera4edd152012-01-06 18:24:04 -0800987 return getBoolean(LOCKOUT_PERMANENT_KEY, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 }
989
990 /**
991 * Set the state of whether the device is permanently locked, meaning the user
Karl Rosaen678771b2009-08-21 14:00:26 -0700992 * must authenticate via other means.
993 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 * @param locked Whether the user is permanently locked out until they verify their
995 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
996 * attempts.
997 */
998 public void setPermanentlyLocked(boolean locked) {
999 setBoolean(LOCKOUT_PERMANENT_KEY, locked);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
1001
John Wang0f7b3f82011-05-31 11:20:55 -07001002 public boolean isEmergencyCallCapable() {
1003 return mContext.getResources().getBoolean(
1004 com.android.internal.R.bool.config_voice_capable);
1005 }
1006
1007 public boolean isPukUnlockScreenEnable() {
1008 return mContext.getResources().getBoolean(
1009 com.android.internal.R.bool.config_enable_puk_unlock_screen);
1010 }
1011
Jim Miller1f56edc2011-11-07 19:00:48 -08001012 public boolean isEmergencyCallEnabledWhileSimLocked() {
1013 return mContext.getResources().getBoolean(
1014 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
1015 }
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 /**
1018 * @return A formatted string of the next alarm (for showing on the lock screen),
1019 * or null if there is no next alarm.
1020 */
1021 public String getNextAlarm() {
Amith Yamasani8fd96ec2012-09-21 17:48:49 -07001022 String nextAlarm = Settings.System.getStringForUser(mContentResolver,
1023 Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
1025 return null;
1026 }
1027 return nextAlarm;
1028 }
1029
Jim Millerf45bb402013-08-20 18:58:32 -07001030 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001031 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001032 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001033 } catch (RemoteException re) {
1034 return defaultValue;
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
1037
Jim Millerf45bb402013-08-20 18:58:32 -07001038 private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
1039 return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
1040 }
1041
1042 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001043 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001044 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001045 } catch (RemoteException re) {
1046 // What can we do?
1047 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1048 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 }
1050
Jim Millerf45bb402013-08-20 18:58:32 -07001051 private void setBoolean(String secureSettingKey, boolean enabled) {
1052 setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
1053 }
1054
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001055 public int[] getAppWidgets() {
Jim Millerf45bb402013-08-20 18:58:32 -07001056 return getAppWidgets(UserHandle.USER_CURRENT);
1057 }
1058
1059 private int[] getAppWidgets(int userId) {
Amith Yamasani8fd96ec2012-09-21 17:48:49 -07001060 String appWidgetIdString = Settings.Secure.getStringForUser(
Jim Millerf45bb402013-08-20 18:58:32 -07001061 mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001062 String delims = ",";
Michael Jurka1254f2f2012-10-25 11:44:31 -07001063 if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001064 String[] appWidgetStringIds = appWidgetIdString.split(delims);
1065 int[] appWidgetIds = new int[appWidgetStringIds.length];
1066 for (int i = 0; i < appWidgetStringIds.length; i++) {
1067 String appWidget = appWidgetStringIds[i];
1068 try {
1069 appWidgetIds[i] = Integer.decode(appWidget);
1070 } catch (NumberFormatException e) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001071 Log.d(TAG, "Error when parsing widget id " + appWidget);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001072 return null;
1073 }
1074 }
1075 return appWidgetIds;
Jim Millerf229e4d2012-09-12 20:32:50 -07001076 }
Michael Jurka67a871d2012-11-01 18:26:01 -07001077 return new int[0];
Jim Millerf229e4d2012-09-12 20:32:50 -07001078 }
1079
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001080 private static String combineStrings(int[] list, String separator) {
1081 int listLength = list.length;
1082
1083 switch (listLength) {
1084 case 0: {
1085 return "";
1086 }
1087 case 1: {
1088 return Integer.toString(list[0]);
1089 }
Michael Jurka20c41d52012-09-20 19:01:06 -07001090 }
1091
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001092 int strLength = 0;
1093 int separatorLength = separator.length();
1094
1095 String[] stringList = new String[list.length];
1096 for (int i = 0; i < listLength; i++) {
1097 stringList[i] = Integer.toString(list[i]);
1098 strLength += stringList[i].length();
1099 if (i < listLength - 1) {
1100 strLength += separatorLength;
1101 }
1102 }
1103
1104 StringBuilder sb = new StringBuilder(strLength);
1105
1106 for (int i = 0; i < listLength; i++) {
1107 sb.append(list[i]);
1108 if (i < listLength - 1) {
1109 sb.append(separator);
1110 }
1111 }
1112
1113 return sb.toString();
1114 }
1115
Jim Miller51117262012-11-04 17:58:09 -08001116 // appwidget used when appwidgets are disabled (we make an exception for
1117 // default clock widget)
1118 public void writeFallbackAppWidgetId(int appWidgetId) {
1119 Settings.Secure.putIntForUser(mContentResolver,
1120 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1121 appWidgetId,
1122 UserHandle.USER_CURRENT);
1123 }
1124
1125 // appwidget used when appwidgets are disabled (we make an exception for
1126 // default clock widget)
1127 public int getFallbackAppWidgetId() {
1128 return Settings.Secure.getIntForUser(
1129 mContentResolver,
1130 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1131 AppWidgetManager.INVALID_APPWIDGET_ID,
1132 UserHandle.USER_CURRENT);
1133 }
1134
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001135 private void writeAppWidgets(int[] appWidgetIds) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001136 Settings.Secure.putStringForUser(mContentResolver,
1137 Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
1138 combineStrings(appWidgetIds, ","),
1139 UserHandle.USER_CURRENT);
1140 }
1141
Michael Jurka1254f2f2012-10-25 11:44:31 -07001142 // TODO: log an error if this returns false
1143 public boolean addAppWidget(int widgetId, int index) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001144 int[] widgets = getAppWidgets();
Michael Jurka1254f2f2012-10-25 11:44:31 -07001145 if (widgets == null) {
1146 return false;
1147 }
Michael Jurka229dd8b2012-10-26 16:06:12 -07001148 if (index < 0 || index > widgets.length) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001149 return false;
1150 }
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001151 int[] newWidgets = new int[widgets.length + 1];
1152 for (int i = 0, j = 0; i < newWidgets.length; i++) {
1153 if (index == i) {
1154 newWidgets[i] = widgetId;
1155 i++;
1156 }
1157 if (i < newWidgets.length) {
1158 newWidgets[i] = widgets[j];
1159 j++;
1160 }
1161 }
1162 writeAppWidgets(newWidgets);
Michael Jurka1254f2f2012-10-25 11:44:31 -07001163 return true;
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001164 }
1165
Michael Jurka1254f2f2012-10-25 11:44:31 -07001166 public boolean removeAppWidget(int widgetId) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001167 int[] widgets = getAppWidgets();
Michael Jurka1254f2f2012-10-25 11:44:31 -07001168
Jim Millera9768602012-11-06 22:17:25 -08001169 if (widgets.length == 0) {
1170 return false;
1171 }
1172
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001173 int[] newWidgets = new int[widgets.length - 1];
1174 for (int i = 0, j = 0; i < widgets.length; i++) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001175 if (widgets[i] == widgetId) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001176 // continue...
Michael Jurka1254f2f2012-10-25 11:44:31 -07001177 } else if (j >= newWidgets.length) {
1178 // we couldn't find the widget
1179 return false;
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001180 } else {
1181 newWidgets[j] = widgets[i];
1182 j++;
1183 }
1184 }
1185 writeAppWidgets(newWidgets);
1186 return true;
Michael Jurka20c41d52012-09-20 19:01:06 -07001187 }
1188
Amith Yamasani52c489c2012-03-28 11:42:42 -07001189 private long getLong(String secureSettingKey, long defaultValue) {
1190 try {
1191 return getLockSettings().getLong(secureSettingKey, defaultValue,
1192 getCurrentOrCallingUserId());
1193 } catch (RemoteException re) {
1194 return defaultValue;
1195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 }
1197
Amith Yamasani156c4352010-03-05 17:10:03 -08001198 private void setLong(String secureSettingKey, long value) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001199 setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1200 }
1201
1202 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001203 try {
1204 getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1205 } catch (RemoteException re) {
1206 // What can we do?
1207 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 }
1210
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001211 private String getString(String secureSettingKey) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001212 return getString(secureSettingKey, getCurrentOrCallingUserId());
1213 }
1214
1215 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001216 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001217 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001218 } catch (RemoteException re) {
1219 return null;
1220 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001221 }
1222
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001223 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001224 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001225 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001226 } catch (RemoteException re) {
1227 // What can we do?
1228 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1229 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001230 }
1231
Jim Miller69aa4a92009-12-22 19:03:28 -08001232 public boolean isSecure() {
Jim Millercd709882010-03-25 18:24:02 -07001233 long mode = getKeyguardStoredPasswordQuality();
1234 final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1235 final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1236 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001237 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1238 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Jim Millercd709882010-03-25 18:24:02 -07001239 final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
Danielle Millett73da5fe2011-09-13 16:20:05 -04001240 || isPassword && savedPasswordExists();
Jim Miller69aa4a92009-12-22 19:03:28 -08001241 return secure;
1242 }
Jim Miller69ac9882010-02-24 15:35:05 -08001243
1244 /**
John Wang0f7b3f82011-05-31 11:20:55 -07001245 * Sets the emergency button visibility based on isEmergencyCallCapable().
1246 *
1247 * If the emergency button is visible, sets the text on the emergency button
1248 * to indicate what action will be taken.
1249 *
Jim Miller69ac9882010-02-24 15:35:05 -08001250 * If there's currently a call in progress, the button will take them to the call
1251 * @param button the button to update
Jim Miller3f5f83b2011-09-26 15:17:05 -07001252 * @param the phone state:
1253 * {@link TelephonyManager#CALL_STATE_IDLE}
1254 * {@link TelephonyManager#CALL_STATE_RINGING}
1255 * {@link TelephonyManager#CALL_STATE_OFFHOOK}
Jim Miller1f56edc2011-11-07 19:00:48 -08001256 * @param shown indicates whether the given screen wants the emergency button to show at all
Jim Miller109f1fd2012-09-19 20:44:16 -07001257 * @param button
1258 * @param phoneState
1259 * @param shown shown if true; hidden if false
1260 * @param upperCase if true, converts button label string to upper case
Jim Miller69ac9882010-02-24 15:35:05 -08001261 */
Jim Miller109f1fd2012-09-19 20:44:16 -07001262 public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown,
Jim Millere38c8e22013-09-24 15:54:04 -07001263 boolean showIcon) {
Jim Miller1f56edc2011-11-07 19:00:48 -08001264 if (isEmergencyCallCapable() && shown) {
John Wang0f7b3f82011-05-31 11:20:55 -07001265 button.setVisibility(View.VISIBLE);
1266 } else {
1267 button.setVisibility(View.GONE);
1268 return;
1269 }
1270
Jim Miller69ac9882010-02-24 15:35:05 -08001271 int textId;
Jim Miller3f5f83b2011-09-26 15:17:05 -07001272 if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
Jim Miller69ac9882010-02-24 15:35:05 -08001273 // show "return to call" text and show phone icon
1274 textId = R.string.lockscreen_return_to_call;
Jim Miller109f1fd2012-09-19 20:44:16 -07001275 int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
Jim Miller69ac9882010-02-24 15:35:05 -08001276 button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
1277 } else {
1278 textId = R.string.lockscreen_emergency_call;
Jim Miller109f1fd2012-09-19 20:44:16 -07001279 int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
Jim Miller69ac9882010-02-24 15:35:05 -08001280 button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
1281 }
Jim Millere38c8e22013-09-24 15:54:04 -07001282 button.setText(textId);
Jim Miller69ac9882010-02-24 15:35:05 -08001283 }
1284
1285 /**
1286 * Resumes a call in progress. Typically launched from the EmergencyCall button
1287 * on various lockscreens.
1288 *
1289 * @return true if we were able to tell InCallScreen to show.
1290 */
1291 public boolean resumeCall() {
1292 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
1293 try {
1294 if (phone != null && phone.showCallScreen()) {
1295 return true;
1296 }
1297 } catch (RemoteException e) {
1298 // What can we do?
1299 }
1300 return false;
1301 }
Danielle Millett044a0a72011-11-07 15:42:12 -05001302
1303 private void finishBiometricWeak() {
1304 setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
1305
1306 // Launch intent to show final screen, this also
1307 // moves the temporary gallery to the actual gallery
1308 Intent intent = new Intent();
1309 intent.setClassName("com.android.facelock",
1310 "com.android.facelock.SetupEndScreen");
1311 mContext.startActivity(intent);
1312 }
1313
Jim Millera4edd152012-01-06 18:24:04 -08001314 public void setPowerButtonInstantlyLocks(boolean enabled) {
1315 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
1316 }
1317
1318 public boolean getPowerButtonInstantlyLocks() {
1319 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
1320 }
Jim Millera9768602012-11-06 22:17:25 -08001321
Jim Miller51117262012-11-04 17:58:09 -08001322 public static boolean isSafeModeEnabled() {
1323 try {
1324 return IWindowManager.Stub.asInterface(
1325 ServiceManager.getService("window")).isSafeModeEnabled();
1326 } catch (RemoteException e) {
1327 // Shouldn't happen!
1328 }
1329 return false;
1330 }
Jim Millera4edd152012-01-06 18:24:04 -08001331
Jim Millerf45bb402013-08-20 18:58:32 -07001332 /**
1333 * Determine whether the user has selected any non-system widgets in keyguard
1334 *
1335 * @return true if widgets have been selected
1336 */
1337 public boolean hasWidgetsEnabledInKeyguard(int userid) {
1338 int widgets[] = getAppWidgets(userid);
1339 for (int i = 0; i < widgets.length; i++) {
1340 if (widgets[i] > 0) {
1341 return true;
1342 }
1343 }
1344 return false;
1345 }
1346
1347 public boolean getWidgetsEnabled() {
1348 return getWidgetsEnabled(getCurrentOrCallingUserId());
1349 }
1350
1351 public boolean getWidgetsEnabled(int userId) {
1352 return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
1353 }
1354
1355 public void setWidgetsEnabled(boolean enabled) {
1356 setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
1357 }
1358
1359 public void setWidgetsEnabled(boolean enabled, int userId) {
1360 setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
1361 }
1362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363}