blob: 521ba8154e63e99312ad8bfcc51aa6d279377bf8 [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;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070035import android.security.KeyStore;
Jim Miller69ac9882010-02-24 15:35:05 -080036import android.telephony.TelephonyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.text.TextUtils;
38import android.util.Log;
Jim Miller51117262012-11-04 17:58:09 -080039import android.view.IWindowManager;
John Wang0f7b3f82011-05-31 11:20:55 -070040import android.view.View;
Jim Miller69ac9882010-02-24 15:35:05 -080041import android.widget.Button;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
Michael Jurka1254f2f2012-10-25 11:44:31 -070043import com.android.internal.R;
44import com.android.internal.telephony.ITelephony;
45import com.google.android.collect.Lists;
Michael Jurkaaa2859a2012-10-24 12:46:49 -070046
Brian Carlstrom929a1c22011-02-01 21:54:09 -080047import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080049import java.security.SecureRandom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import java.util.List;
51
52/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070053 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 */
55public class LockPatternUtils {
56
57 private static final String TAG = "LockPatternUtils";
Jim Miller69aa4a92009-12-22 19:03:28 -080058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 /**
60 * The maximum number of incorrect attempts before the user is prevented
61 * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
62 */
63 public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
64
65 /**
66 * The number of incorrect attempts before which we fall back on an alternative
67 * method of verifying the user, and resetting their lock pattern.
68 */
69 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
70
71 /**
72 * How long the user is prevented from trying again after entering the
73 * wrong pattern too many times.
74 */
75 public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
76
77 /**
78 * The interval of the countdown for showing progress of the lockout.
79 */
80 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
81
Jim Miller4f369952011-08-19 18:29:22 -070082
83 /**
84 * This dictates when we start telling the user that continued failed attempts will wipe
85 * their device.
86 */
87 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 /**
90 * The minimum number of dots in a valid pattern.
91 */
92 public static final int MIN_LOCK_PATTERN_SIZE = 4;
93
94 /**
95 * The minimum number of dots the user must include in a wrong pattern
96 * attempt for it to be counted against the counts that affect
97 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
98 */
Jim Miller4f369952011-08-19 18:29:22 -070099 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Danielle Millett925a7d82012-03-19 18:02:20 -0400101 /**
Adam Cohenf7522022012-10-03 20:03:18 -0700102 * Tells the keyguard to show the user switcher when the keyguard is created.
103 */
104 public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
105
106 /**
107 * Tells the keyguard to show the security challenge when the keyguard is created.
108 */
109 public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
110
111 /**
Michael Jurka76017ca2012-11-06 16:21:09 -0800112 * Tells the keyguard to show the widget with the specified id when the keyguard is created.
113 */
114 public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
115
116 /**
Danielle Millett925a7d82012-03-19 18:02:20 -0400117 * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
118 * be used
119 */
120 public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
121
Michael Jurka1254f2f2012-10-25 11:44:31 -0700122 /**
123 * Pseudo-appwidget id we use to represent the default clock status widget
124 */
125 public static final int ID_DEFAULT_STATUS_WIDGET = -2;
126
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800127 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
128 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
129 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800130 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Jim Miller6edf2632011-09-05 16:03:14 -0700131 public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800132 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
133 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
134 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Jim Miller6edf2632011-09-05 16:03:14 -0700135 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
136 = "lockscreen.biometric_weak_fallback";
Danielle Millett7a072192011-10-03 17:36:01 -0400137 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
138 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800139 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
140 = "lockscreen.power_button_instantly_locks";
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 {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700294 final boolean matched = getLockSettings().checkPattern(patternToHash(pattern), userId);
295 if (matched && (userId == UserHandle.USER_OWNER)) {
296 KeyStore.getInstance().password(patternToString(pattern));
297 }
298 return matched;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700299 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 return true;
301 }
302 }
303
304 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800305 * Check to see if a password matches the saved password. If no password exists,
306 * always returns true.
307 * @param password The password to check.
308 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800310 public boolean checkPassword(String password) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700311 final int userId = getCurrentOrCallingUserId();
Jim Miller69aa4a92009-12-22 19:03:28 -0800312 try {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700313 final boolean matched = getLockSettings().checkPassword(passwordToHash(password),
314 userId);
315 if (matched && (userId == UserHandle.USER_OWNER)) {
316 KeyStore.getInstance().password(password);
317 }
318 return matched;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700319 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800320 return true;
321 }
322 }
323
324 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700325 * Check to see if a password matches any of the passwords stored in the
326 * password history.
327 *
328 * @param password The password to check.
329 * @return Whether the password matches any in the history.
330 */
331 public boolean checkPasswordHistory(String password) {
332 String passwordHashString = new String(passwordToHash(password));
333 String passwordHistory = getString(PASSWORD_HISTORY_KEY);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700334 if (passwordHistory == null) {
335 return false;
336 }
337 // Password History may be too long...
338 int passwordHashLength = passwordHashString.length();
339 int passwordHistoryLength = getRequestedPasswordHistoryLength();
340 if(passwordHistoryLength == 0) {
341 return false;
342 }
343 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
344 + passwordHistoryLength - 1;
345 if (passwordHistory.length() > neededPasswordHistoryLength) {
346 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
347 }
348 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700349 }
350
351 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800352 * Check to see if the user has stored a lock pattern.
353 * @return Whether a saved pattern exists.
354 */
355 public boolean savedPatternExists() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700356 try {
357 return getLockSettings().havePattern(getCurrentOrCallingUserId());
358 } catch (RemoteException re) {
359 return false;
360 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800361 }
362
363 /**
364 * Check to see if the user has stored a lock pattern.
365 * @return Whether a saved pattern exists.
366 */
367 public boolean savedPasswordExists() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700368 try {
369 return getLockSettings().havePassword(getCurrentOrCallingUserId());
370 } catch (RemoteException re) {
371 return false;
372 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800373 }
374
375 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700376 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
377 * currently cleared.
378 *
379 * @return True if the user has ever chosen a pattern.
380 */
381 public boolean isPatternEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800382 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700383 }
384
385 /**
Danielle Millett7a072192011-10-03 17:36:01 -0400386 * Return true if the user has ever chosen biometric weak. This is true even if biometric
387 * weak is not current set.
388 *
389 * @return True if the user has ever chosen biometric weak.
390 */
391 public boolean isBiometricWeakEverChosen() {
Jim Millera4edd152012-01-06 18:24:04 -0800392 return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
Danielle Millett7a072192011-10-03 17:36:01 -0400393 }
394
395 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700396 * Used by device policy manager to validate the current password
397 * information it has.
398 */
399 public int getActivePasswordQuality() {
Jim Millercd709882010-03-25 18:24:02 -0700400 int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400401 // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
402 // return biometric_weak if that is being used instead of the backup
403 int quality =
404 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
405 switch (quality) {
Jim Millercd709882010-03-25 18:24:02 -0700406 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700407 if (isLockPatternEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700408 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700409 }
Jim Millercd709882010-03-25 18:24:02 -0700410 break;
Danielle Millettc8fb5322011-10-04 12:18:51 -0400411 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
412 if (isBiometricWeakInstalled()) {
413 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
414 }
415 break;
Jim Millercd709882010-03-25 18:24:02 -0700416 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700417 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700418 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700419 }
Jim Millercd709882010-03-25 18:24:02 -0700420 break;
421 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700422 if (isLockPasswordEnabled()) {
Jim Millercd709882010-03-25 18:24:02 -0700423 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700424 }
Jim Millercd709882010-03-25 18:24:02 -0700425 break;
426 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
427 if (isLockPasswordEnabled()) {
428 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
429 }
430 break;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700431 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
432 if (isLockPasswordEnabled()) {
433 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
434 }
435 break;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700436 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400437
Jim Millercd709882010-03-25 18:24:02 -0700438 return activePasswordQuality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700439 }
Jim Millercd709882010-03-25 18:24:02 -0700440
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700441 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800442 * Clear any lock pattern or password.
443 */
Steven Ross329979c2011-09-28 11:42:56 -0400444 public void clearLock(boolean isFallback) {
445 if(!isFallback) deleteGallery();
Jim Millercd709882010-03-25 18:24:02 -0700446 saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800447 setLockPatternEnabled(false);
448 saveLockPattern(null);
Jim Miller93708af12012-01-25 18:26:12 -0800449 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Jim Miller6edf2632011-09-05 16:03:14 -0700450 setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800451 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800452
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800453 /**
Jim Miller2a98a4c2010-11-19 18:49:26 -0800454 * Disable showing lock screen at all when the DevicePolicyManager allows it.
455 * This is only meaningful if pattern, pin or password are not set.
456 *
457 * @param disable Disables lock screen when true
458 */
459 public void setLockScreenDisabled(boolean disable) {
460 setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
461 }
462
463 /**
464 * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
465 * show LockScreen or go straight to the home screen.
466 *
467 * @return true if lock screen is can be disabled
468 */
469 public boolean isLockScreenDisabled() {
470 return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
471 }
472
473 /**
Steven Ross3553c292011-09-30 15:48:40 -0400474 * Calls back SetupFaceLock to delete the temporary gallery file
Steven Ross329979c2011-09-28 11:42:56 -0400475 */
476 public void deleteTempGallery() {
Danielle Millett574e49e2012-03-27 16:17:10 -0400477 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
Steven Ross3553c292011-09-30 15:48:40 -0400478 intent.putExtra("deleteTempGallery", true);
Danielle Millett574e49e2012-03-27 16:17:10 -0400479 mContext.sendBroadcast(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400480 }
481
482 /**
483 * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
484 */
485 void deleteGallery() {
Danielle Millett58396982011-09-30 13:55:07 -0400486 if(usingBiometricWeak()) {
Danielle Millett574e49e2012-03-27 16:17:10 -0400487 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
Steven Ross329979c2011-09-28 11:42:56 -0400488 intent.putExtra("deleteGallery", true);
Danielle Millett574e49e2012-03-27 16:17:10 -0400489 mContext.sendBroadcast(intent);
Steven Ross329979c2011-09-28 11:42:56 -0400490 }
491 }
492
493 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700494 * Save a lock pattern.
495 * @param pattern The new pattern to save.
Danielle Millett2364a222011-12-21 17:02:32 -0500496 */
497 public void saveLockPattern(List<LockPatternView.Cell> pattern) {
498 this.saveLockPattern(pattern, false);
499 }
500
501 /**
502 * Save a lock pattern.
503 * @param pattern The new pattern to save.
Jim Miller6edf2632011-09-05 16:03:14 -0700504 * @param isFallback Specifies if this is a fallback to biometric weak
505 */
506 public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 // Compute the hash
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700508 final byte[] hash = LockPatternUtils.patternToHash(pattern);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 try {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700510 getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId());
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800511 DevicePolicyManager dpm = getDevicePolicyManager();
Brian Carlstrome2afc242011-06-02 16:21:55 -0700512 KeyStore keyStore = KeyStore.getInstance();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800513 if (pattern != null) {
Brian Carlstrome2afc242011-06-02 16:21:55 -0700514 keyStore.password(patternToString(pattern));
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800515 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
Jim Miller6edf2632011-09-05 16:03:14 -0700516 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400517 deleteGallery();
Jim Miller6edf2632011-09-05 16:03:14 -0700518 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett2364a222011-12-21 17:02:32 -0500519 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700520 pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700521 } else {
522 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
523 setLong(PASSWORD_TYPE_ALTERNATE_KEY,
524 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
Danielle Millett044a0a72011-11-07 15:42:12 -0500525 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500526 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700527 0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700528 }
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800529 } else {
Brian Carlstrome2afc242011-06-02 16:21:55 -0700530 if (keyStore.isEmpty()) {
531 keyStore.reset();
532 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700533 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700534 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800535 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700536 } catch (RemoteException re) {
537 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 }
539 }
540
Jim Miller187ec582013-04-15 18:27:54 -0700541 public void setOwnerInfo(String info, int userId) {
542 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
543 }
544
545 public void setOwnerInfoEnabled(boolean enabled) {
546 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
547 }
548
549 public String getOwnerInfo(int userId) {
550 return getString(LOCK_SCREEN_OWNER_INFO);
551 }
552
553 public boolean isOwnerInfoEnabled() {
554 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
555 }
556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700558 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800559 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700560 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800561 boolean hasDigit = false;
562 boolean hasNonDigit = false;
563 final int len = password.length();
564 for (int i = 0; i < len; i++) {
565 if (Character.isDigit(password.charAt(i))) {
566 hasDigit = true;
567 } else {
568 hasNonDigit = true;
569 }
570 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800571
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700572 if (hasNonDigit && hasDigit) {
573 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800574 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800575 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700576 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800577 }
578 if (hasDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700579 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800580 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700581 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800582 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800583
Jason parksf7b3cd42011-01-27 09:28:25 -0600584 /** Update the encryption password if it is enabled **/
585 private void updateEncryptionPassword(String password) {
586 DevicePolicyManager dpm = getDevicePolicyManager();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700587 if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
588 != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600589 return;
590 }
591
592 IBinder service = ServiceManager.getService("mount");
593 if (service == null) {
594 Log.e(TAG, "Could not find the mount service to update the encryption password");
595 return;
596 }
597
598 IMountService mountService = IMountService.Stub.asInterface(service);
599 try {
600 mountService.changeEncryptionPassword(password);
601 } catch (RemoteException e) {
602 Log.e(TAG, "Error changing encryption password", e);
603 }
604 }
605
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800606 /**
Jim Millercd709882010-03-25 18:24:02 -0700607 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800608 * as the requested mode, but will adjust the mode to be as good as the
609 * pattern.
Jim Miller69aa4a92009-12-22 19:03:28 -0800610 * @param password The password to save
Jim Millercd709882010-03-25 18:24:02 -0700611 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Jim Miller69aa4a92009-12-22 19:03:28 -0800612 */
Jim Millercd709882010-03-25 18:24:02 -0700613 public void saveLockPassword(String password, int quality) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700614 this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700615 }
616
617 /**
618 * Save a lock password. Does not ensure that the password is as good
619 * as the requested mode, but will adjust the mode to be as good as the
620 * pattern.
621 * @param password The password to save
622 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
623 * @param isFallback Specifies if this is a fallback to biometric weak
624 */
625 public void saveLockPassword(String password, int quality, boolean isFallback) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700626 saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
627 }
628
629 /**
630 * Save a lock password. Does not ensure that the password is as good
631 * as the requested mode, but will adjust the mode to be as good as the
632 * pattern.
633 * @param password The password to save
634 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
635 * @param isFallback Specifies if this is a fallback to biometric weak
636 * @param userHandle The userId of the user to change the password for
637 */
638 public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800639 // Compute the hash
Jim Miller11b019d2010-01-20 16:34:45 -0800640 final byte[] hash = passwordToHash(password);
Jim Miller69aa4a92009-12-22 19:03:28 -0800641 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700642 getLockSettings().setLockPassword(hash, userHandle);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800643 DevicePolicyManager dpm = getDevicePolicyManager();
Brian Carlstrome2afc242011-06-02 16:21:55 -0700644 KeyStore keyStore = KeyStore.getInstance();
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800645 if (password != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700646 if (userHandle == UserHandle.USER_OWNER) {
647 // Update the encryption password.
648 updateEncryptionPassword(password);
Jason parksf7b3cd42011-01-27 09:28:25 -0600649
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700650 // Update the keystore password
651 keyStore.password(password);
652 }
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700653
Jim Millercd709882010-03-25 18:24:02 -0700654 int computedQuality = computePasswordQuality(password);
Jim Miller6edf2632011-09-05 16:03:14 -0700655 if (!isFallback) {
Steven Ross329979c2011-09-28 11:42:56 -0400656 deleteGallery();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700657 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500658 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
659 int letters = 0;
660 int uppercase = 0;
661 int lowercase = 0;
662 int numbers = 0;
663 int symbols = 0;
664 int nonletter = 0;
665 for (int i = 0; i < password.length(); i++) {
666 char c = password.charAt(i);
667 if (c >= 'A' && c <= 'Z') {
668 letters++;
669 uppercase++;
670 } else if (c >= 'a' && c <= 'z') {
671 letters++;
672 lowercase++;
673 } else if (c >= '0' && c <= '9') {
674 numbers++;
675 nonletter++;
676 } else {
677 symbols++;
678 nonletter++;
679 }
680 }
681 dpm.setActivePasswordState(Math.max(quality, computedQuality),
682 password.length(), letters, uppercase, lowercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700683 numbers, symbols, nonletter, userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500684 } else {
685 // The password is not anything.
686 dpm.setActivePasswordState(
687 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700688 0, 0, 0, 0, 0, 0, 0, userHandle);
Danielle Millett2364a222011-12-21 17:02:32 -0500689 }
Jim Miller6edf2632011-09-05 16:03:14 -0700690 } else {
Danielle Millett2364a222011-12-21 17:02:32 -0500691 // Case where it's a fallback for biometric weak
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700692 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
693 userHandle);
694 setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
695 userHandle);
Danielle Millett044a0a72011-11-07 15:42:12 -0500696 finishBiometricWeak();
Danielle Millett2364a222011-12-21 17:02:32 -0500697 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700698 0, 0, 0, 0, 0, 0, 0, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700699 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700700 // Add the password to the password history. We assume all
701 // password
702 // hashes have the same length for simplicity of implementation.
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700703 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700704 if (passwordHistory == null) {
705 passwordHistory = new String();
706 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700707 int passwordHistoryLength = getRequestedPasswordHistoryLength();
708 if (passwordHistoryLength == 0) {
709 passwordHistory = "";
710 } else {
711 passwordHistory = new String(hash) + "," + passwordHistory;
712 // Cut it to contain passwordHistoryLength hashes
713 // and passwordHistoryLength -1 commas.
714 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
715 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
716 .length()));
717 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700718 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800719 } else {
Brian Carlstrome2afc242011-06-02 16:21:55 -0700720 // Conditionally reset the keystore if empty. If
721 // non-empty, we are just switching key guard type
722 if (keyStore.isEmpty()) {
723 keyStore.reset();
724 }
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800725 dpm.setActivePasswordState(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700726 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
727 userHandle);
Jim Miller31f90b62010-01-20 13:35:20 -0800728 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700729 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800730 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700731 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800732 }
733 }
734
Jim Millercd709882010-03-25 18:24:02 -0700735 /**
736 * Retrieves the quality mode we're in.
737 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
738 *
739 * @return stored password quality
740 */
741 public int getKeyguardStoredPasswordQuality() {
Jim Miller6edf2632011-09-05 16:03:14 -0700742 int quality =
743 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
744 // If the user has chosen to use weak biometric sensor, then return the backup locking
745 // method and treat biometric as a special case.
746 if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
747 quality =
748 (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
749 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
750 }
751 return quality;
752 }
753
Danielle Millett58396982011-09-30 13:55:07 -0400754 /**
755 * @return true if the lockscreen method is set to biometric weak
756 */
Jim Miller6edf2632011-09-05 16:03:14 -0700757 public boolean usingBiometricWeak() {
758 int quality =
759 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
760 return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
Jim Miller69aa4a92009-12-22 19:03:28 -0800761 }
762
763 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 * Deserialize a pattern.
765 * @param string The pattern serialized with {@link #patternToString}
766 * @return The pattern.
767 */
768 public static List<LockPatternView.Cell> stringToPattern(String string) {
769 List<LockPatternView.Cell> result = Lists.newArrayList();
770
771 final byte[] bytes = string.getBytes();
772 for (int i = 0; i < bytes.length; i++) {
773 byte b = bytes[i];
774 result.add(LockPatternView.Cell.of(b / 3, b % 3));
775 }
776 return result;
777 }
778
779 /**
780 * Serialize a pattern.
781 * @param pattern The pattern.
782 * @return The pattern in string form.
783 */
784 public static String patternToString(List<LockPatternView.Cell> pattern) {
785 if (pattern == null) {
786 return "";
787 }
788 final int patternSize = pattern.size();
789
790 byte[] res = new byte[patternSize];
791 for (int i = 0; i < patternSize; i++) {
792 LockPatternView.Cell cell = pattern.get(i);
793 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
794 }
795 return new String(res);
796 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 /*
799 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
800 * at least a second level of protection. First level is that the file
801 * is in a location only readable by the system process.
802 * @param pattern the gesture pattern.
803 * @return the hash of the pattern in a byte array.
804 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800805 private static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 if (pattern == null) {
807 return null;
808 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 final int patternSize = pattern.size();
811 byte[] res = new byte[patternSize];
812 for (int i = 0; i < patternSize; i++) {
813 LockPatternView.Cell cell = pattern.get(i);
814 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
815 }
816 try {
817 MessageDigest md = MessageDigest.getInstance("SHA-1");
818 byte[] hash = md.digest(res);
819 return hash;
820 } catch (NoSuchAlgorithmException nsa) {
821 return res;
822 }
823 }
824
Jim Miller11b019d2010-01-20 16:34:45 -0800825 private String getSalt() {
826 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
827 if (salt == 0) {
828 try {
829 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
830 setLong(LOCK_PASSWORD_SALT_KEY, salt);
831 Log.v(TAG, "Initialized lock password salt");
832 } catch (NoSuchAlgorithmException e) {
833 // Throw an exception rather than storing a password we'll never be able to recover
834 throw new IllegalStateException("Couldn't get SecureRandom number", e);
835 }
836 }
837 return Long.toHexString(salt);
838 }
839
Jim Miller69aa4a92009-12-22 19:03:28 -0800840 /*
841 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
842 * Not the most secure, but it is at least a second level of protection. First level is that
843 * the file is in a location only readable by the system process.
844 * @param password the gesture pattern.
845 * @return the hash of the pattern in a byte array.
846 */
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700847 public byte[] passwordToHash(String password) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800848 if (password == null) {
849 return null;
850 }
851 String algo = null;
852 byte[] hashed = null;
853 try {
Jim Miller11b019d2010-01-20 16:34:45 -0800854 byte[] saltedPassword = (password + getSalt()).getBytes();
Jim Miller69aa4a92009-12-22 19:03:28 -0800855 byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
856 byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
857 hashed = (toHex(sha1) + toHex(md5)).getBytes();
858 } catch (NoSuchAlgorithmException e) {
859 Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
860 }
861 return hashed;
862 }
863
864 private static String toHex(byte[] ary) {
865 final String hex = "0123456789ABCDEF";
866 String ret = "";
867 for (int i = 0; i < ary.length; i++) {
868 ret += hex.charAt((ary[i] >> 4) & 0xf);
869 ret += hex.charAt(ary[i] & 0xf);
870 }
871 return ret;
872 }
873
874 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400875 * @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 -0800876 */
877 public boolean isLockPasswordEnabled() {
878 long mode = getLong(PASSWORD_TYPE_KEY, 0);
Danielle Millett73da5fe2011-09-13 16:20:05 -0400879 long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
880 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
881 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
882 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
883 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
884 final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
885 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
886 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
887 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
888
889 return savedPasswordExists() && (passwordEnabled ||
Danielle Millett58396982011-09-30 13:55:07 -0400890 (usingBiometricWeak() && backupEnabled));
Jim Miller69aa4a92009-12-22 19:03:28 -0800891 }
892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 /**
Danielle Millett73da5fe2011-09-13 16:20:05 -0400894 * @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 -0800895 */
896 public boolean isLockPatternEnabled() {
Danielle Millett73da5fe2011-09-13 16:20:05 -0400897 final boolean backupEnabled =
898 getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
899 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
900
Jim Millera4edd152012-01-06 18:24:04 -0800901 return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
Danielle Millett73da5fe2011-09-13 16:20:05 -0400902 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
903 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
Danielle Millett58396982011-09-30 13:55:07 -0400904 (usingBiometricWeak() && backupEnabled));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 }
906
907 /**
Danielle Millett58396982011-09-30 13:55:07 -0400908 * @return Whether biometric weak lock is installed and that the front facing camera exists
Jim Miller6edf2632011-09-05 16:03:14 -0700909 */
Danielle Millett58396982011-09-30 13:55:07 -0400910 public boolean isBiometricWeakInstalled() {
Danielle Millett58396982011-09-30 13:55:07 -0400911 // Check that it's installed
912 PackageManager pm = mContext.getPackageManager();
913 try {
914 pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
915 } catch (PackageManager.NameNotFoundException e) {
916 return false;
917 }
918
919 // Check that the camera is enabled
920 if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
921 return false;
922 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700923 if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
Danielle Millett58396982011-09-30 13:55:07 -0400924 return false;
925 }
926
927
928 return true;
Jim Miller6edf2632011-09-05 16:03:14 -0700929 }
930
931 /**
Danielle Millett925a7d82012-03-19 18:02:20 -0400932 * Set whether biometric weak liveliness is enabled.
933 */
934 public void setBiometricWeakLivelinessEnabled(boolean enabled) {
935 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
936 long newFlag;
937 if (enabled) {
938 newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
939 } else {
940 newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
941 }
942 setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
943 }
944
945 /**
946 * @return Whether the biometric weak liveliness is enabled.
947 */
948 public boolean isBiometricWeakLivelinessEnabled() {
949 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
950 return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
951 }
952
953 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 * Set whether the lock pattern is enabled.
955 */
956 public void setLockPatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800957 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 }
959
960 /**
961 * @return Whether the visible pattern is enabled.
962 */
963 public boolean isVisiblePatternEnabled() {
Jim Millera4edd152012-01-06 18:24:04 -0800964 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 }
966
967 /**
968 * Set whether the visible pattern is enabled.
969 */
970 public void setVisiblePatternEnabled(boolean enabled) {
Amith Yamasani156c4352010-03-05 17:10:03 -0800971 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973
974 /**
975 * @return Whether tactile feedback for the pattern is enabled.
976 */
977 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -0700978 return Settings.System.getIntForUser(mContentResolver,
979 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981
982 /**
983 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
984 * pattern until the deadline has passed.
985 * @return the chosen deadline.
986 */
987 public long setLockoutAttemptDeadline() {
988 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
989 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
990 return deadline;
991 }
992
993 /**
994 * @return The elapsed time in millis in the future when the user is allowed to
995 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
996 * enter a pattern.
997 */
998 public long getLockoutAttemptDeadline() {
999 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
1000 final long now = SystemClock.elapsedRealtime();
1001 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
1002 return 0L;
1003 }
1004 return deadline;
1005 }
1006
1007 /**
1008 * @return Whether the user is permanently locked out until they verify their
1009 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
1010 * attempts.
1011 */
1012 public boolean isPermanentlyLocked() {
Jim Millera4edd152012-01-06 18:24:04 -08001013 return getBoolean(LOCKOUT_PERMANENT_KEY, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 }
1015
1016 /**
1017 * Set the state of whether the device is permanently locked, meaning the user
Karl Rosaen678771b2009-08-21 14:00:26 -07001018 * must authenticate via other means.
1019 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 * @param locked Whether the user is permanently locked out until they verify their
1021 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
1022 * attempts.
1023 */
1024 public void setPermanentlyLocked(boolean locked) {
1025 setBoolean(LOCKOUT_PERMANENT_KEY, locked);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027
John Wang0f7b3f82011-05-31 11:20:55 -07001028 public boolean isEmergencyCallCapable() {
1029 return mContext.getResources().getBoolean(
1030 com.android.internal.R.bool.config_voice_capable);
1031 }
1032
1033 public boolean isPukUnlockScreenEnable() {
1034 return mContext.getResources().getBoolean(
1035 com.android.internal.R.bool.config_enable_puk_unlock_screen);
1036 }
1037
Jim Miller1f56edc2011-11-07 19:00:48 -08001038 public boolean isEmergencyCallEnabledWhileSimLocked() {
1039 return mContext.getResources().getBoolean(
1040 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
1041 }
1042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 /**
1044 * @return A formatted string of the next alarm (for showing on the lock screen),
1045 * or null if there is no next alarm.
1046 */
1047 public String getNextAlarm() {
Amith Yamasani8fd96ec2012-09-21 17:48:49 -07001048 String nextAlarm = Settings.System.getStringForUser(mContentResolver,
1049 Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
1051 return null;
1052 }
1053 return nextAlarm;
1054 }
1055
Jim Millera4edd152012-01-06 18:24:04 -08001056 private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001057 try {
1058 return getLockSettings().getBoolean(secureSettingKey, defaultValue,
1059 getCurrentOrCallingUserId());
1060 } catch (RemoteException re) {
1061 return defaultValue;
1062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
1064
Amith Yamasani156c4352010-03-05 17:10:03 -08001065 private void setBoolean(String secureSettingKey, boolean enabled) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001066 try {
1067 getLockSettings().setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
1068 } catch (RemoteException re) {
1069 // What can we do?
1070 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001074 public int[] getAppWidgets() {
Amith Yamasani8fd96ec2012-09-21 17:48:49 -07001075 String appWidgetIdString = Settings.Secure.getStringForUser(
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001076 mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
Amith Yamasani8fd96ec2012-09-21 17:48:49 -07001077 UserHandle.USER_CURRENT);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001078 String delims = ",";
Michael Jurka1254f2f2012-10-25 11:44:31 -07001079 if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001080 String[] appWidgetStringIds = appWidgetIdString.split(delims);
1081 int[] appWidgetIds = new int[appWidgetStringIds.length];
1082 for (int i = 0; i < appWidgetStringIds.length; i++) {
1083 String appWidget = appWidgetStringIds[i];
1084 try {
1085 appWidgetIds[i] = Integer.decode(appWidget);
1086 } catch (NumberFormatException e) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001087 Log.d(TAG, "Error when parsing widget id " + appWidget);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001088 return null;
1089 }
1090 }
1091 return appWidgetIds;
Jim Millerf229e4d2012-09-12 20:32:50 -07001092 }
Michael Jurka67a871d2012-11-01 18:26:01 -07001093 return new int[0];
Jim Millerf229e4d2012-09-12 20:32:50 -07001094 }
1095
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001096 private static String combineStrings(int[] list, String separator) {
1097 int listLength = list.length;
1098
1099 switch (listLength) {
1100 case 0: {
1101 return "";
1102 }
1103 case 1: {
1104 return Integer.toString(list[0]);
1105 }
Michael Jurka20c41d52012-09-20 19:01:06 -07001106 }
1107
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001108 int strLength = 0;
1109 int separatorLength = separator.length();
1110
1111 String[] stringList = new String[list.length];
1112 for (int i = 0; i < listLength; i++) {
1113 stringList[i] = Integer.toString(list[i]);
1114 strLength += stringList[i].length();
1115 if (i < listLength - 1) {
1116 strLength += separatorLength;
1117 }
1118 }
1119
1120 StringBuilder sb = new StringBuilder(strLength);
1121
1122 for (int i = 0; i < listLength; i++) {
1123 sb.append(list[i]);
1124 if (i < listLength - 1) {
1125 sb.append(separator);
1126 }
1127 }
1128
1129 return sb.toString();
1130 }
1131
Jim Miller51117262012-11-04 17:58:09 -08001132 // appwidget used when appwidgets are disabled (we make an exception for
1133 // default clock widget)
1134 public void writeFallbackAppWidgetId(int appWidgetId) {
1135 Settings.Secure.putIntForUser(mContentResolver,
1136 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1137 appWidgetId,
1138 UserHandle.USER_CURRENT);
1139 }
1140
1141 // appwidget used when appwidgets are disabled (we make an exception for
1142 // default clock widget)
1143 public int getFallbackAppWidgetId() {
1144 return Settings.Secure.getIntForUser(
1145 mContentResolver,
1146 Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
1147 AppWidgetManager.INVALID_APPWIDGET_ID,
1148 UserHandle.USER_CURRENT);
1149 }
1150
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001151 private void writeAppWidgets(int[] appWidgetIds) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001152 Settings.Secure.putStringForUser(mContentResolver,
1153 Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
1154 combineStrings(appWidgetIds, ","),
1155 UserHandle.USER_CURRENT);
1156 }
1157
Michael Jurka1254f2f2012-10-25 11:44:31 -07001158 // TODO: log an error if this returns false
1159 public boolean addAppWidget(int widgetId, int index) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001160 int[] widgets = getAppWidgets();
Michael Jurka1254f2f2012-10-25 11:44:31 -07001161 if (widgets == null) {
1162 return false;
1163 }
Michael Jurka229dd8b2012-10-26 16:06:12 -07001164 if (index < 0 || index > widgets.length) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001165 return false;
1166 }
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001167 int[] newWidgets = new int[widgets.length + 1];
1168 for (int i = 0, j = 0; i < newWidgets.length; i++) {
1169 if (index == i) {
1170 newWidgets[i] = widgetId;
1171 i++;
1172 }
1173 if (i < newWidgets.length) {
1174 newWidgets[i] = widgets[j];
1175 j++;
1176 }
1177 }
1178 writeAppWidgets(newWidgets);
Michael Jurka1254f2f2012-10-25 11:44:31 -07001179 return true;
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001180 }
1181
Michael Jurka1254f2f2012-10-25 11:44:31 -07001182 public boolean removeAppWidget(int widgetId) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001183 int[] widgets = getAppWidgets();
Michael Jurka1254f2f2012-10-25 11:44:31 -07001184
Jim Millera9768602012-11-06 22:17:25 -08001185 if (widgets.length == 0) {
1186 return false;
1187 }
1188
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001189 int[] newWidgets = new int[widgets.length - 1];
1190 for (int i = 0, j = 0; i < widgets.length; i++) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001191 if (widgets[i] == widgetId) {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001192 // continue...
Michael Jurka1254f2f2012-10-25 11:44:31 -07001193 } else if (j >= newWidgets.length) {
1194 // we couldn't find the widget
1195 return false;
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001196 } else {
1197 newWidgets[j] = widgets[i];
1198 j++;
1199 }
1200 }
1201 writeAppWidgets(newWidgets);
1202 return true;
Michael Jurka20c41d52012-09-20 19:01:06 -07001203 }
1204
Amith Yamasani52c489c2012-03-28 11:42:42 -07001205 private long getLong(String secureSettingKey, long defaultValue) {
1206 try {
1207 return getLockSettings().getLong(secureSettingKey, defaultValue,
1208 getCurrentOrCallingUserId());
1209 } catch (RemoteException re) {
1210 return defaultValue;
1211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
1213
Amith Yamasani156c4352010-03-05 17:10:03 -08001214 private void setLong(String secureSettingKey, long value) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001215 setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1216 }
1217
1218 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001219 try {
1220 getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1221 } catch (RemoteException re) {
1222 // What can we do?
1223 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 }
1226
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001227 private String getString(String secureSettingKey) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001228 return getString(secureSettingKey, getCurrentOrCallingUserId());
1229 }
1230
1231 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001232 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001233 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001234 } catch (RemoteException re) {
1235 return null;
1236 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001237 }
1238
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001239 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001240 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001241 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001242 } catch (RemoteException re) {
1243 // What can we do?
1244 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1245 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001246 }
1247
Jim Miller69aa4a92009-12-22 19:03:28 -08001248 public boolean isSecure() {
Jim Millercd709882010-03-25 18:24:02 -07001249 long mode = getKeyguardStoredPasswordQuality();
1250 final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1251 final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1252 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001253 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1254 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Jim Millercd709882010-03-25 18:24:02 -07001255 final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
Danielle Millett73da5fe2011-09-13 16:20:05 -04001256 || isPassword && savedPasswordExists();
Jim Miller69aa4a92009-12-22 19:03:28 -08001257 return secure;
1258 }
Jim Miller69ac9882010-02-24 15:35:05 -08001259
1260 /**
John Wang0f7b3f82011-05-31 11:20:55 -07001261 * Sets the emergency button visibility based on isEmergencyCallCapable().
1262 *
1263 * If the emergency button is visible, sets the text on the emergency button
1264 * to indicate what action will be taken.
1265 *
Jim Miller69ac9882010-02-24 15:35:05 -08001266 * If there's currently a call in progress, the button will take them to the call
1267 * @param button the button to update
Jim Miller3f5f83b2011-09-26 15:17:05 -07001268 * @param the phone state:
1269 * {@link TelephonyManager#CALL_STATE_IDLE}
1270 * {@link TelephonyManager#CALL_STATE_RINGING}
1271 * {@link TelephonyManager#CALL_STATE_OFFHOOK}
Jim Miller1f56edc2011-11-07 19:00:48 -08001272 * @param shown indicates whether the given screen wants the emergency button to show at all
Jim Miller109f1fd2012-09-19 20:44:16 -07001273 * @param button
1274 * @param phoneState
1275 * @param shown shown if true; hidden if false
1276 * @param upperCase if true, converts button label string to upper case
Jim Miller69ac9882010-02-24 15:35:05 -08001277 */
Jim Miller109f1fd2012-09-19 20:44:16 -07001278 public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown,
1279 boolean upperCase, boolean showIcon) {
Jim Miller1f56edc2011-11-07 19:00:48 -08001280 if (isEmergencyCallCapable() && shown) {
John Wang0f7b3f82011-05-31 11:20:55 -07001281 button.setVisibility(View.VISIBLE);
1282 } else {
1283 button.setVisibility(View.GONE);
1284 return;
1285 }
1286
Jim Miller69ac9882010-02-24 15:35:05 -08001287 int textId;
Jim Miller3f5f83b2011-09-26 15:17:05 -07001288 if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
Jim Miller69ac9882010-02-24 15:35:05 -08001289 // show "return to call" text and show phone icon
1290 textId = R.string.lockscreen_return_to_call;
Jim Miller109f1fd2012-09-19 20:44:16 -07001291 int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
Jim Miller69ac9882010-02-24 15:35:05 -08001292 button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
1293 } else {
1294 textId = R.string.lockscreen_emergency_call;
Jim Miller109f1fd2012-09-19 20:44:16 -07001295 int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
Jim Miller69ac9882010-02-24 15:35:05 -08001296 button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
1297 }
Jim Miller109f1fd2012-09-19 20:44:16 -07001298 if (upperCase) {
1299 CharSequence original = mContext.getResources().getText(textId);
1300 String upper = original != null ? original.toString().toUpperCase() : null;
1301 button.setText(upper);
1302 } else {
1303 button.setText(textId);
1304 }
1305 }
1306
1307 /**
1308 * @deprecated
1309 * @param button
1310 * @param phoneState
1311 * @param shown
1312 */
1313 public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
1314 updateEmergencyCallButtonState(button, phoneState, shown, false, true);
Jim Miller69ac9882010-02-24 15:35:05 -08001315 }
1316
1317 /**
1318 * Resumes a call in progress. Typically launched from the EmergencyCall button
1319 * on various lockscreens.
1320 *
1321 * @return true if we were able to tell InCallScreen to show.
1322 */
1323 public boolean resumeCall() {
1324 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
1325 try {
1326 if (phone != null && phone.showCallScreen()) {
1327 return true;
1328 }
1329 } catch (RemoteException e) {
1330 // What can we do?
1331 }
1332 return false;
1333 }
Danielle Millett044a0a72011-11-07 15:42:12 -05001334
1335 private void finishBiometricWeak() {
1336 setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
1337
1338 // Launch intent to show final screen, this also
1339 // moves the temporary gallery to the actual gallery
1340 Intent intent = new Intent();
1341 intent.setClassName("com.android.facelock",
1342 "com.android.facelock.SetupEndScreen");
1343 mContext.startActivity(intent);
1344 }
1345
Jim Millera4edd152012-01-06 18:24:04 -08001346 public void setPowerButtonInstantlyLocks(boolean enabled) {
1347 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
1348 }
1349
1350 public boolean getPowerButtonInstantlyLocks() {
1351 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
1352 }
Jim Millera9768602012-11-06 22:17:25 -08001353
Jim Miller51117262012-11-04 17:58:09 -08001354 public static boolean isSafeModeEnabled() {
1355 try {
1356 return IWindowManager.Stub.asInterface(
1357 ServiceManager.getService("window")).isSafeModeEnabled();
1358 } catch (RemoteException e) {
1359 // Shouldn't happen!
1360 }
1361 return false;
1362 }
Jim Millera4edd152012-01-06 18:24:04 -08001363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364}