LockPatternUtils.java revision 1254f2f42f7173ef51d0034975ab5cb7d44f8209
1/* 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 19import android.app.ActivityManagerNative; 20import android.app.admin.DevicePolicyManager; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.PackageManager; 25import android.os.Binder; 26import android.os.Bundle; 27import android.os.IBinder; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.os.SystemClock; 31import android.os.UserHandle; 32import android.os.storage.IMountService; 33import android.provider.Settings; 34import android.security.KeyStore; 35import android.telephony.TelephonyManager; 36import android.text.TextUtils; 37import android.util.Log; 38import android.view.View; 39import android.widget.Button; 40 41import com.android.internal.R; 42import com.android.internal.telephony.ITelephony; 43import com.google.android.collect.Lists; 44 45import java.security.MessageDigest; 46import java.security.NoSuchAlgorithmException; 47import java.security.SecureRandom; 48import java.util.List; 49 50/** 51 * Utilities for the lock pattern and its settings. 52 */ 53public class LockPatternUtils { 54 55 private static final String OPTION_ENABLE_FACELOCK = "enable_facelock"; 56 57 private static final String TAG = "LockPatternUtils"; 58 59 /** 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 82 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 89 /** 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 */ 99 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE; 100 101 /** 102 * 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 /** 112 * Options used to lock the device upon user switch. 113 */ 114 public static final Bundle USER_SWITCH_LOCK_OPTIONS = new Bundle(); 115 116 static { 117 USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_USER_SWITCHER, true); 118 USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_SECURITY_CHALLENGE, true); 119 } 120 121 /** 122 * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should 123 * be used 124 */ 125 public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1; 126 127 /** 128 * Pseudo-appwidget id we use to represent the default clock status widget 129 */ 130 public static final int ID_DEFAULT_STATUS_WIDGET = -2; 131 132 protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; 133 protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; 134 protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; 135 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type"; 136 public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate"; 137 protected final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt"; 138 protected final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled"; 139 protected final static String LOCKSCREEN_OPTIONS = "lockscreen.options"; 140 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK 141 = "lockscreen.biometric_weak_fallback"; 142 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY 143 = "lockscreen.biometricweakeverchosen"; 144 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS 145 = "lockscreen.power_button_instantly_locks"; 146 147 protected final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory"; 148 149 private final Context mContext; 150 private final ContentResolver mContentResolver; 151 private DevicePolicyManager mDevicePolicyManager; 152 private ILockSettings mLockSettingsService; 153 154 // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils. 155 private static volatile int sCurrentUserId = UserHandle.USER_NULL; 156 157 public DevicePolicyManager getDevicePolicyManager() { 158 if (mDevicePolicyManager == null) { 159 mDevicePolicyManager = 160 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 161 if (mDevicePolicyManager == null) { 162 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?", 163 new IllegalStateException("Stack trace:")); 164 } 165 } 166 return mDevicePolicyManager; 167 } 168 169 /** 170 * @param contentResolver Used to look up and save settings. 171 */ 172 public LockPatternUtils(Context context) { 173 mContext = context; 174 mContentResolver = context.getContentResolver(); 175 } 176 177 private ILockSettings getLockSettings() { 178 if (mLockSettingsService == null) { 179 mLockSettingsService = ILockSettings.Stub.asInterface( 180 (IBinder) ServiceManager.getService("lock_settings")); 181 } 182 return mLockSettingsService; 183 } 184 185 public int getRequestedMinimumPasswordLength() { 186 return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId()); 187 } 188 189 /** 190 * Gets the device policy password mode. If the mode is non-specific, returns 191 * MODE_PATTERN which allows the user to choose anything. 192 */ 193 public int getRequestedPasswordQuality() { 194 return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId()); 195 } 196 197 public int getRequestedPasswordHistoryLength() { 198 return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId()); 199 } 200 201 public int getRequestedPasswordMinimumLetters() { 202 return getDevicePolicyManager().getPasswordMinimumLetters(null, 203 getCurrentOrCallingUserId()); 204 } 205 206 public int getRequestedPasswordMinimumUpperCase() { 207 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, 208 getCurrentOrCallingUserId()); 209 } 210 211 public int getRequestedPasswordMinimumLowerCase() { 212 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, 213 getCurrentOrCallingUserId()); 214 } 215 216 public int getRequestedPasswordMinimumNumeric() { 217 return getDevicePolicyManager().getPasswordMinimumNumeric(null, 218 getCurrentOrCallingUserId()); 219 } 220 221 public int getRequestedPasswordMinimumSymbols() { 222 return getDevicePolicyManager().getPasswordMinimumSymbols(null, 223 getCurrentOrCallingUserId()); 224 } 225 226 public int getRequestedPasswordMinimumNonLetter() { 227 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, 228 getCurrentOrCallingUserId()); 229 } 230 231 /** 232 * Returns the actual password mode, as set by keyguard after updating the password. 233 * 234 * @return 235 */ 236 public void reportFailedPasswordAttempt() { 237 getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId()); 238 } 239 240 public void reportSuccessfulPasswordAttempt() { 241 getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId()); 242 } 243 244 public void setCurrentUser(int userId) { 245 sCurrentUserId = userId; 246 } 247 248 public int getCurrentUser() { 249 if (sCurrentUserId != UserHandle.USER_NULL) { 250 // Someone is regularly updating using setCurrentUser() use that value. 251 return sCurrentUserId; 252 } 253 try { 254 return ActivityManagerNative.getDefault().getCurrentUser().id; 255 } catch (RemoteException re) { 256 return UserHandle.USER_OWNER; 257 } 258 } 259 260 public void removeUser(int userId) { 261 try { 262 getLockSettings().removeUser(userId); 263 } catch (RemoteException re) { 264 Log.e(TAG, "Couldn't remove lock settings for user " + userId); 265 } 266 } 267 268 private int getCurrentOrCallingUserId() { 269 int callingUid = Binder.getCallingUid(); 270 if (callingUid == android.os.Process.SYSTEM_UID) { 271 // TODO: This is a little inefficient. See if all users of this are able to 272 // handle USER_CURRENT and pass that instead. 273 return getCurrentUser(); 274 } else { 275 return UserHandle.getUserId(callingUid); 276 } 277 } 278 279 /** 280 * Check to see if a pattern matches the saved pattern. If no pattern exists, 281 * always returns true. 282 * @param pattern The pattern to check. 283 * @return Whether the pattern matches the stored one. 284 */ 285 public boolean checkPattern(List<LockPatternView.Cell> pattern) { 286 final int userId = getCurrentOrCallingUserId(); 287 try { 288 final boolean matched = getLockSettings().checkPattern(patternToHash(pattern), userId); 289 if (matched && (userId == UserHandle.USER_OWNER)) { 290 KeyStore.getInstance().password(patternToString(pattern)); 291 } 292 return matched; 293 } catch (RemoteException re) { 294 return true; 295 } 296 } 297 298 /** 299 * Check to see if a password matches the saved password. If no password exists, 300 * always returns true. 301 * @param password The password to check. 302 * @return Whether the password matches the stored one. 303 */ 304 public boolean checkPassword(String password) { 305 final int userId = getCurrentOrCallingUserId(); 306 try { 307 final boolean matched = getLockSettings().checkPassword(passwordToHash(password), 308 userId); 309 if (matched && (userId == UserHandle.USER_OWNER)) { 310 KeyStore.getInstance().password(password); 311 } 312 return matched; 313 } catch (RemoteException re) { 314 return true; 315 } 316 } 317 318 /** 319 * Check to see if a password matches any of the passwords stored in the 320 * password history. 321 * 322 * @param password The password to check. 323 * @return Whether the password matches any in the history. 324 */ 325 public boolean checkPasswordHistory(String password) { 326 String passwordHashString = new String(passwordToHash(password)); 327 String passwordHistory = getString(PASSWORD_HISTORY_KEY); 328 if (passwordHistory == null) { 329 return false; 330 } 331 // Password History may be too long... 332 int passwordHashLength = passwordHashString.length(); 333 int passwordHistoryLength = getRequestedPasswordHistoryLength(); 334 if(passwordHistoryLength == 0) { 335 return false; 336 } 337 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength 338 + passwordHistoryLength - 1; 339 if (passwordHistory.length() > neededPasswordHistoryLength) { 340 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength); 341 } 342 return passwordHistory.contains(passwordHashString); 343 } 344 345 /** 346 * Check to see if the user has stored a lock pattern. 347 * @return Whether a saved pattern exists. 348 */ 349 public boolean savedPatternExists() { 350 try { 351 return getLockSettings().havePattern(getCurrentOrCallingUserId()); 352 } catch (RemoteException re) { 353 return false; 354 } 355 } 356 357 /** 358 * Check to see if the user has stored a lock pattern. 359 * @return Whether a saved pattern exists. 360 */ 361 public boolean savedPasswordExists() { 362 try { 363 return getLockSettings().havePassword(getCurrentOrCallingUserId()); 364 } catch (RemoteException re) { 365 return false; 366 } 367 } 368 369 /** 370 * Return true if the user has ever chosen a pattern. This is true even if the pattern is 371 * currently cleared. 372 * 373 * @return True if the user has ever chosen a pattern. 374 */ 375 public boolean isPatternEverChosen() { 376 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false); 377 } 378 379 /** 380 * Return true if the user has ever chosen biometric weak. This is true even if biometric 381 * weak is not current set. 382 * 383 * @return True if the user has ever chosen biometric weak. 384 */ 385 public boolean isBiometricWeakEverChosen() { 386 return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false); 387 } 388 389 /** 390 * Used by device policy manager to validate the current password 391 * information it has. 392 */ 393 public int getActivePasswordQuality() { 394 int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 395 // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to 396 // return biometric_weak if that is being used instead of the backup 397 int quality = 398 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 399 switch (quality) { 400 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 401 if (isLockPatternEnabled()) { 402 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 403 } 404 break; 405 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK: 406 if (isBiometricWeakInstalled()) { 407 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK; 408 } 409 break; 410 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 411 if (isLockPasswordEnabled()) { 412 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 413 } 414 break; 415 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 416 if (isLockPasswordEnabled()) { 417 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; 418 } 419 break; 420 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 421 if (isLockPasswordEnabled()) { 422 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; 423 } 424 break; 425 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 426 if (isLockPasswordEnabled()) { 427 activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 428 } 429 break; 430 } 431 432 return activePasswordQuality; 433 } 434 435 /** 436 * Clear any lock pattern or password. 437 */ 438 public void clearLock(boolean isFallback) { 439 if(!isFallback) deleteGallery(); 440 saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 441 setLockPatternEnabled(false); 442 saveLockPattern(null); 443 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 444 setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 445 } 446 447 /** 448 * Disable showing lock screen at all when the DevicePolicyManager allows it. 449 * This is only meaningful if pattern, pin or password are not set. 450 * 451 * @param disable Disables lock screen when true 452 */ 453 public void setLockScreenDisabled(boolean disable) { 454 setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0); 455 } 456 457 /** 458 * Determine if LockScreen can be disabled. This is used, for example, to tell if we should 459 * show LockScreen or go straight to the home screen. 460 * 461 * @return true if lock screen is can be disabled 462 */ 463 public boolean isLockScreenDisabled() { 464 return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0; 465 } 466 467 /** 468 * Calls back SetupFaceLock to delete the temporary gallery file 469 */ 470 public void deleteTempGallery() { 471 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY"); 472 intent.putExtra("deleteTempGallery", true); 473 mContext.sendBroadcast(intent); 474 } 475 476 /** 477 * Calls back SetupFaceLock to delete the gallery file when the lock type is changed 478 */ 479 void deleteGallery() { 480 if(usingBiometricWeak()) { 481 Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY"); 482 intent.putExtra("deleteGallery", true); 483 mContext.sendBroadcast(intent); 484 } 485 } 486 487 /** 488 * Save a lock pattern. 489 * @param pattern The new pattern to save. 490 */ 491 public void saveLockPattern(List<LockPatternView.Cell> pattern) { 492 this.saveLockPattern(pattern, false); 493 } 494 495 /** 496 * Save a lock pattern. 497 * @param pattern The new pattern to save. 498 * @param isFallback Specifies if this is a fallback to biometric weak 499 */ 500 public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) { 501 // Compute the hash 502 final byte[] hash = LockPatternUtils.patternToHash(pattern); 503 try { 504 getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId()); 505 DevicePolicyManager dpm = getDevicePolicyManager(); 506 KeyStore keyStore = KeyStore.getInstance(); 507 if (pattern != null) { 508 keyStore.password(patternToString(pattern)); 509 setBoolean(PATTERN_EVER_CHOSEN_KEY, true); 510 if (!isFallback) { 511 deleteGallery(); 512 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 513 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 514 pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); 515 } else { 516 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK); 517 setLong(PASSWORD_TYPE_ALTERNATE_KEY, 518 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 519 finishBiometricWeak(); 520 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, 521 0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); 522 } 523 } else { 524 if (keyStore.isEmpty()) { 525 keyStore.reset(); 526 } 527 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 528 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); 529 } 530 } catch (RemoteException re) { 531 Log.e(TAG, "Couldn't save lock pattern " + re); 532 } 533 } 534 535 /** 536 * Compute the password quality from the given password string. 537 */ 538 static public int computePasswordQuality(String password) { 539 boolean hasDigit = false; 540 boolean hasNonDigit = false; 541 final int len = password.length(); 542 for (int i = 0; i < len; i++) { 543 if (Character.isDigit(password.charAt(i))) { 544 hasDigit = true; 545 } else { 546 hasNonDigit = true; 547 } 548 } 549 550 if (hasNonDigit && hasDigit) { 551 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; 552 } 553 if (hasNonDigit) { 554 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; 555 } 556 if (hasDigit) { 557 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 558 } 559 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 560 } 561 562 /** Update the encryption password if it is enabled **/ 563 private void updateEncryptionPassword(String password) { 564 DevicePolicyManager dpm = getDevicePolicyManager(); 565 if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId()) 566 != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) { 567 return; 568 } 569 570 IBinder service = ServiceManager.getService("mount"); 571 if (service == null) { 572 Log.e(TAG, "Could not find the mount service to update the encryption password"); 573 return; 574 } 575 576 IMountService mountService = IMountService.Stub.asInterface(service); 577 try { 578 mountService.changeEncryptionPassword(password); 579 } catch (RemoteException e) { 580 Log.e(TAG, "Error changing encryption password", e); 581 } 582 } 583 584 /** 585 * Save a lock password. Does not ensure that the password is as good 586 * as the requested mode, but will adjust the mode to be as good as the 587 * pattern. 588 * @param password The password to save 589 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} 590 */ 591 public void saveLockPassword(String password, int quality) { 592 this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId()); 593 } 594 595 /** 596 * Save a lock password. Does not ensure that the password is as good 597 * as the requested mode, but will adjust the mode to be as good as the 598 * pattern. 599 * @param password The password to save 600 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} 601 * @param isFallback Specifies if this is a fallback to biometric weak 602 */ 603 public void saveLockPassword(String password, int quality, boolean isFallback) { 604 saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId()); 605 } 606 607 /** 608 * Save a lock password. Does not ensure that the password is as good 609 * as the requested mode, but will adjust the mode to be as good as the 610 * pattern. 611 * @param password The password to save 612 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} 613 * @param isFallback Specifies if this is a fallback to biometric weak 614 * @param userHandle The userId of the user to change the password for 615 */ 616 public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) { 617 // Compute the hash 618 final byte[] hash = passwordToHash(password); 619 try { 620 getLockSettings().setLockPassword(hash, userHandle); 621 DevicePolicyManager dpm = getDevicePolicyManager(); 622 KeyStore keyStore = KeyStore.getInstance(); 623 if (password != null) { 624 if (userHandle == UserHandle.USER_OWNER) { 625 // Update the encryption password. 626 updateEncryptionPassword(password); 627 628 // Update the keystore password 629 keyStore.password(password); 630 } 631 632 int computedQuality = computePasswordQuality(password); 633 if (!isFallback) { 634 deleteGallery(); 635 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); 636 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, 661 numbers, symbols, nonletter, userHandle); 662 } else { 663 // The password is not anything. 664 dpm.setActivePasswordState( 665 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 666 0, 0, 0, 0, 0, 0, 0, userHandle); 667 } 668 } else { 669 // Case where it's a fallback for biometric weak 670 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, 671 userHandle); 672 setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality), 673 userHandle); 674 finishBiometricWeak(); 675 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, 676 0, 0, 0, 0, 0, 0, 0, userHandle); 677 } 678 // Add the password to the password history. We assume all 679 // password 680 // hashes have the same length for simplicity of implementation. 681 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); 682 if (passwordHistory == null) { 683 passwordHistory = new String(); 684 } 685 int passwordHistoryLength = getRequestedPasswordHistoryLength(); 686 if (passwordHistoryLength == 0) { 687 passwordHistory = ""; 688 } else { 689 passwordHistory = new String(hash) + "," + passwordHistory; 690 // Cut it to contain passwordHistoryLength hashes 691 // and passwordHistoryLength -1 commas. 692 passwordHistory = passwordHistory.substring(0, Math.min(hash.length 693 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory 694 .length())); 695 } 696 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle); 697 } else { 698 // Conditionally reset the keystore if empty. If 699 // non-empty, we are just switching key guard type 700 if (keyStore.isEmpty()) { 701 keyStore.reset(); 702 } 703 dpm.setActivePasswordState( 704 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, 705 userHandle); 706 } 707 } catch (RemoteException re) { 708 // Cant do much 709 Log.e(TAG, "Unable to save lock password " + re); 710 } 711 } 712 713 /** 714 * Retrieves the quality mode we're in. 715 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} 716 * 717 * @return stored password quality 718 */ 719 public int getKeyguardStoredPasswordQuality() { 720 int quality = 721 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 722 // If the user has chosen to use weak biometric sensor, then return the backup locking 723 // method and treat biometric as a special case. 724 if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) { 725 quality = 726 (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY, 727 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 728 } 729 return quality; 730 } 731 732 /** 733 * @return true if the lockscreen method is set to biometric weak 734 */ 735 public boolean usingBiometricWeak() { 736 int quality = 737 (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 738 return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK; 739 } 740 741 /** 742 * Deserialize a pattern. 743 * @param string The pattern serialized with {@link #patternToString} 744 * @return The pattern. 745 */ 746 public static List<LockPatternView.Cell> stringToPattern(String string) { 747 List<LockPatternView.Cell> result = Lists.newArrayList(); 748 749 final byte[] bytes = string.getBytes(); 750 for (int i = 0; i < bytes.length; i++) { 751 byte b = bytes[i]; 752 result.add(LockPatternView.Cell.of(b / 3, b % 3)); 753 } 754 return result; 755 } 756 757 /** 758 * Serialize a pattern. 759 * @param pattern The pattern. 760 * @return The pattern in string form. 761 */ 762 public static String patternToString(List<LockPatternView.Cell> pattern) { 763 if (pattern == null) { 764 return ""; 765 } 766 final int patternSize = pattern.size(); 767 768 byte[] res = new byte[patternSize]; 769 for (int i = 0; i < patternSize; i++) { 770 LockPatternView.Cell cell = pattern.get(i); 771 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); 772 } 773 return new String(res); 774 } 775 776 /* 777 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is 778 * at least a second level of protection. First level is that the file 779 * is in a location only readable by the system process. 780 * @param pattern the gesture pattern. 781 * @return the hash of the pattern in a byte array. 782 */ 783 private static byte[] patternToHash(List<LockPatternView.Cell> pattern) { 784 if (pattern == null) { 785 return null; 786 } 787 788 final int patternSize = pattern.size(); 789 byte[] res = new byte[patternSize]; 790 for (int i = 0; i < patternSize; i++) { 791 LockPatternView.Cell cell = pattern.get(i); 792 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); 793 } 794 try { 795 MessageDigest md = MessageDigest.getInstance("SHA-1"); 796 byte[] hash = md.digest(res); 797 return hash; 798 } catch (NoSuchAlgorithmException nsa) { 799 return res; 800 } 801 } 802 803 private String getSalt() { 804 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0); 805 if (salt == 0) { 806 try { 807 salt = SecureRandom.getInstance("SHA1PRNG").nextLong(); 808 setLong(LOCK_PASSWORD_SALT_KEY, salt); 809 Log.v(TAG, "Initialized lock password salt"); 810 } catch (NoSuchAlgorithmException e) { 811 // Throw an exception rather than storing a password we'll never be able to recover 812 throw new IllegalStateException("Couldn't get SecureRandom number", e); 813 } 814 } 815 return Long.toHexString(salt); 816 } 817 818 /* 819 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. 820 * Not the most secure, but it is at least a second level of protection. First level is that 821 * the file is in a location only readable by the system process. 822 * @param password the gesture pattern. 823 * @return the hash of the pattern in a byte array. 824 */ 825 public byte[] passwordToHash(String password) { 826 if (password == null) { 827 return null; 828 } 829 String algo = null; 830 byte[] hashed = null; 831 try { 832 byte[] saltedPassword = (password + getSalt()).getBytes(); 833 byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword); 834 byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword); 835 hashed = (toHex(sha1) + toHex(md5)).getBytes(); 836 } catch (NoSuchAlgorithmException e) { 837 Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo); 838 } 839 return hashed; 840 } 841 842 private static String toHex(byte[] ary) { 843 final String hex = "0123456789ABCDEF"; 844 String ret = ""; 845 for (int i = 0; i < ary.length; i++) { 846 ret += hex.charAt((ary[i] >> 4) & 0xf); 847 ret += hex.charAt(ary[i] & 0xf); 848 } 849 return ret; 850 } 851 852 /** 853 * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak 854 */ 855 public boolean isLockPasswordEnabled() { 856 long mode = getLong(PASSWORD_TYPE_KEY, 0); 857 long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0); 858 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC 859 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC 860 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC 861 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 862 final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC 863 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC 864 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC 865 || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 866 867 return savedPasswordExists() && (passwordEnabled || 868 (usingBiometricWeak() && backupEnabled)); 869 } 870 871 /** 872 * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak 873 */ 874 public boolean isLockPatternEnabled() { 875 final boolean backupEnabled = 876 getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) 877 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 878 879 return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false) 880 && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) 881 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING || 882 (usingBiometricWeak() && backupEnabled)); 883 } 884 885 /** 886 * @return Whether biometric weak lock is installed and that the front facing camera exists 887 */ 888 public boolean isBiometricWeakInstalled() { 889 // Check that it's installed 890 PackageManager pm = mContext.getPackageManager(); 891 try { 892 pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES); 893 } catch (PackageManager.NameNotFoundException e) { 894 return false; 895 } 896 897 // Check that the camera is enabled 898 if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) { 899 return false; 900 } 901 if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) { 902 return false; 903 } 904 905 906 return true; 907 } 908 909 /** 910 * Set whether biometric weak liveliness is enabled. 911 */ 912 public void setBiometricWeakLivelinessEnabled(boolean enabled) { 913 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L); 914 long newFlag; 915 if (enabled) { 916 newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS; 917 } else { 918 newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS; 919 } 920 setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag); 921 } 922 923 /** 924 * @return Whether the biometric weak liveliness is enabled. 925 */ 926 public boolean isBiometricWeakLivelinessEnabled() { 927 long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L); 928 return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0); 929 } 930 931 /** 932 * Set whether the lock pattern is enabled. 933 */ 934 public void setLockPatternEnabled(boolean enabled) { 935 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled); 936 } 937 938 /** 939 * @return Whether the visible pattern is enabled. 940 */ 941 public boolean isVisiblePatternEnabled() { 942 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false); 943 } 944 945 /** 946 * Set whether the visible pattern is enabled. 947 */ 948 public void setVisiblePatternEnabled(boolean enabled) { 949 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled); 950 } 951 952 /** 953 * @return Whether tactile feedback for the pattern is enabled. 954 */ 955 public boolean isTactileFeedbackEnabled() { 956 return Settings.System.getIntForUser(mContentResolver, 957 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0; 958 } 959 960 /** 961 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock 962 * pattern until the deadline has passed. 963 * @return the chosen deadline. 964 */ 965 public long setLockoutAttemptDeadline() { 966 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS; 967 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline); 968 return deadline; 969 } 970 971 /** 972 * @return The elapsed time in millis in the future when the user is allowed to 973 * attempt to enter his/her lock pattern, or 0 if the user is welcome to 974 * enter a pattern. 975 */ 976 public long getLockoutAttemptDeadline() { 977 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L); 978 final long now = SystemClock.elapsedRealtime(); 979 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) { 980 return 0L; 981 } 982 return deadline; 983 } 984 985 /** 986 * @return Whether the user is permanently locked out until they verify their 987 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed 988 * attempts. 989 */ 990 public boolean isPermanentlyLocked() { 991 return getBoolean(LOCKOUT_PERMANENT_KEY, false); 992 } 993 994 /** 995 * Set the state of whether the device is permanently locked, meaning the user 996 * must authenticate via other means. 997 * 998 * @param locked Whether the user is permanently locked out until they verify their 999 * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed 1000 * attempts. 1001 */ 1002 public void setPermanentlyLocked(boolean locked) { 1003 setBoolean(LOCKOUT_PERMANENT_KEY, locked); 1004 } 1005 1006 public boolean isEmergencyCallCapable() { 1007 return mContext.getResources().getBoolean( 1008 com.android.internal.R.bool.config_voice_capable); 1009 } 1010 1011 public boolean isPukUnlockScreenEnable() { 1012 return mContext.getResources().getBoolean( 1013 com.android.internal.R.bool.config_enable_puk_unlock_screen); 1014 } 1015 1016 public boolean isEmergencyCallEnabledWhileSimLocked() { 1017 return mContext.getResources().getBoolean( 1018 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked); 1019 } 1020 1021 /** 1022 * @return A formatted string of the next alarm (for showing on the lock screen), 1023 * or null if there is no next alarm. 1024 */ 1025 public String getNextAlarm() { 1026 String nextAlarm = Settings.System.getStringForUser(mContentResolver, 1027 Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT); 1028 if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) { 1029 return null; 1030 } 1031 return nextAlarm; 1032 } 1033 1034 private boolean getBoolean(String secureSettingKey, boolean defaultValue) { 1035 try { 1036 return getLockSettings().getBoolean(secureSettingKey, defaultValue, 1037 getCurrentOrCallingUserId()); 1038 } catch (RemoteException re) { 1039 return defaultValue; 1040 } 1041 } 1042 1043 private void setBoolean(String secureSettingKey, boolean enabled) { 1044 try { 1045 getLockSettings().setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId()); 1046 } catch (RemoteException re) { 1047 // What can we do? 1048 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re); 1049 } 1050 } 1051 1052 public int[] getAppWidgets() { 1053 String appWidgetIdString = Settings.Secure.getStringForUser( 1054 mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, 1055 UserHandle.USER_CURRENT); 1056 String delims = ","; 1057 if (appWidgetIdString != null && appWidgetIdString.length() > 0) { 1058 String[] appWidgetStringIds = appWidgetIdString.split(delims); 1059 int[] appWidgetIds = new int[appWidgetStringIds.length]; 1060 for (int i = 0; i < appWidgetStringIds.length; i++) { 1061 String appWidget = appWidgetStringIds[i]; 1062 try { 1063 appWidgetIds[i] = Integer.decode(appWidget); 1064 } catch (NumberFormatException e) { 1065 Log.d(TAG, "Error when parsing widget id " + appWidget); 1066 return null; 1067 } 1068 } 1069 return appWidgetIds; 1070 } 1071 if (appWidgetIdString == null) { 1072 return new int[] { LockPatternUtils.ID_DEFAULT_STATUS_WIDGET }; 1073 } else { 1074 return new int[0]; 1075 } 1076 } 1077 1078 private static String combineStrings(int[] list, String separator) { 1079 int listLength = list.length; 1080 1081 switch (listLength) { 1082 case 0: { 1083 return ""; 1084 } 1085 case 1: { 1086 return Integer.toString(list[0]); 1087 } 1088 } 1089 1090 int strLength = 0; 1091 int separatorLength = separator.length(); 1092 1093 String[] stringList = new String[list.length]; 1094 for (int i = 0; i < listLength; i++) { 1095 stringList[i] = Integer.toString(list[i]); 1096 strLength += stringList[i].length(); 1097 if (i < listLength - 1) { 1098 strLength += separatorLength; 1099 } 1100 } 1101 1102 StringBuilder sb = new StringBuilder(strLength); 1103 1104 for (int i = 0; i < listLength; i++) { 1105 sb.append(list[i]); 1106 if (i < listLength - 1) { 1107 sb.append(separator); 1108 } 1109 } 1110 1111 return sb.toString(); 1112 } 1113 1114 private void writeAppWidgets(int[] appWidgetIds) { 1115 Settings.Secure.putStringForUser(mContentResolver, 1116 Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, 1117 combineStrings(appWidgetIds, ","), 1118 UserHandle.USER_CURRENT); 1119 } 1120 1121 // TODO: log an error if this returns false 1122 public boolean addAppWidget(int widgetId, int index) { 1123 int[] widgets = getAppWidgets(); 1124 if (widgets == null) { 1125 return false; 1126 } 1127 if (index < 0 || index >= widgets.length) { 1128 return false; 1129 } 1130 int[] newWidgets = new int[widgets.length + 1]; 1131 for (int i = 0, j = 0; i < newWidgets.length; i++) { 1132 if (index == i) { 1133 newWidgets[i] = widgetId; 1134 i++; 1135 } 1136 if (i < newWidgets.length) { 1137 newWidgets[i] = widgets[j]; 1138 j++; 1139 } 1140 } 1141 writeAppWidgets(newWidgets); 1142 return true; 1143 } 1144 1145 public boolean removeAppWidget(int widgetId) { 1146 int[] widgets = getAppWidgets(); 1147 1148 int[] newWidgets = new int[widgets.length - 1]; 1149 for (int i = 0, j = 0; i < widgets.length; i++) { 1150 if (widgets[i] == widgetId) { 1151 // continue... 1152 } else if (j >= newWidgets.length) { 1153 // we couldn't find the widget 1154 return false; 1155 } else { 1156 newWidgets[j] = widgets[i]; 1157 j++; 1158 } 1159 } 1160 writeAppWidgets(newWidgets); 1161 return true; 1162 } 1163 1164 private long getLong(String secureSettingKey, long defaultValue) { 1165 try { 1166 return getLockSettings().getLong(secureSettingKey, defaultValue, 1167 getCurrentOrCallingUserId()); 1168 } catch (RemoteException re) { 1169 return defaultValue; 1170 } 1171 } 1172 1173 private void setLong(String secureSettingKey, long value) { 1174 setLong(secureSettingKey, value, getCurrentOrCallingUserId()); 1175 } 1176 1177 private void setLong(String secureSettingKey, long value, int userHandle) { 1178 try { 1179 getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId()); 1180 } catch (RemoteException re) { 1181 // What can we do? 1182 Log.e(TAG, "Couldn't write long " + secureSettingKey + re); 1183 } 1184 } 1185 1186 private String getString(String secureSettingKey) { 1187 return getString(secureSettingKey, getCurrentOrCallingUserId()); 1188 } 1189 1190 private String getString(String secureSettingKey, int userHandle) { 1191 try { 1192 return getLockSettings().getString(secureSettingKey, null, userHandle); 1193 } catch (RemoteException re) { 1194 return null; 1195 } 1196 } 1197 1198 private void setString(String secureSettingKey, String value, int userHandle) { 1199 try { 1200 getLockSettings().setString(secureSettingKey, value, userHandle); 1201 } catch (RemoteException re) { 1202 // What can we do? 1203 Log.e(TAG, "Couldn't write string " + secureSettingKey + re); 1204 } 1205 } 1206 1207 public boolean isSecure() { 1208 long mode = getKeyguardStoredPasswordQuality(); 1209 final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 1210 final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC 1211 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC 1212 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC 1213 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 1214 final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists() 1215 || isPassword && savedPasswordExists(); 1216 return secure; 1217 } 1218 1219 /** 1220 * Sets the emergency button visibility based on isEmergencyCallCapable(). 1221 * 1222 * If the emergency button is visible, sets the text on the emergency button 1223 * to indicate what action will be taken. 1224 * 1225 * If there's currently a call in progress, the button will take them to the call 1226 * @param button the button to update 1227 * @param the phone state: 1228 * {@link TelephonyManager#CALL_STATE_IDLE} 1229 * {@link TelephonyManager#CALL_STATE_RINGING} 1230 * {@link TelephonyManager#CALL_STATE_OFFHOOK} 1231 * @param shown indicates whether the given screen wants the emergency button to show at all 1232 * @param button 1233 * @param phoneState 1234 * @param shown shown if true; hidden if false 1235 * @param upperCase if true, converts button label string to upper case 1236 */ 1237 public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown, 1238 boolean upperCase, boolean showIcon) { 1239 if (isEmergencyCallCapable() && shown) { 1240 button.setVisibility(View.VISIBLE); 1241 } else { 1242 button.setVisibility(View.GONE); 1243 return; 1244 } 1245 1246 int textId; 1247 if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) { 1248 // show "return to call" text and show phone icon 1249 textId = R.string.lockscreen_return_to_call; 1250 int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0; 1251 button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0); 1252 } else { 1253 textId = R.string.lockscreen_emergency_call; 1254 int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0; 1255 button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0); 1256 } 1257 if (upperCase) { 1258 CharSequence original = mContext.getResources().getText(textId); 1259 String upper = original != null ? original.toString().toUpperCase() : null; 1260 button.setText(upper); 1261 } else { 1262 button.setText(textId); 1263 } 1264 } 1265 1266 /** 1267 * @deprecated 1268 * @param button 1269 * @param phoneState 1270 * @param shown 1271 */ 1272 public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) { 1273 updateEmergencyCallButtonState(button, phoneState, shown, false, true); 1274 } 1275 1276 /** 1277 * Resumes a call in progress. Typically launched from the EmergencyCall button 1278 * on various lockscreens. 1279 * 1280 * @return true if we were able to tell InCallScreen to show. 1281 */ 1282 public boolean resumeCall() { 1283 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 1284 try { 1285 if (phone != null && phone.showCallScreen()) { 1286 return true; 1287 } 1288 } catch (RemoteException e) { 1289 // What can we do? 1290 } 1291 return false; 1292 } 1293 1294 private void finishBiometricWeak() { 1295 setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true); 1296 1297 // Launch intent to show final screen, this also 1298 // moves the temporary gallery to the actual gallery 1299 Intent intent = new Intent(); 1300 intent.setClassName("com.android.facelock", 1301 "com.android.facelock.SetupEndScreen"); 1302 mContext.startActivity(intent); 1303 } 1304 1305 public void setPowerButtonInstantlyLocks(boolean enabled) { 1306 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled); 1307 } 1308 1309 public boolean getPowerButtonInstantlyLocks() { 1310 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true); 1311 } 1312 1313} 1314