ChooseLockGeneric.java revision 91e0ba7d40f6768d19d1e9a32145847af88c6a8c
1/* 2 * Copyright (C) 2010 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.settings; 18 19import android.accessibilityservice.AccessibilityServiceInfo; 20import android.app.Activity; 21import android.app.AlertDialog; 22import android.app.Dialog; 23import android.app.DialogFragment; 24import android.app.Fragment; 25import android.app.FragmentManager; 26import android.app.admin.DevicePolicyManager; 27import android.content.Context; 28import android.content.DialogInterface; 29import android.content.Intent; 30import android.hardware.fingerprint.Fingerprint; 31import android.hardware.fingerprint.FingerprintManager; 32import android.hardware.fingerprint.FingerprintManager.RemovalCallback; 33import android.os.Bundle; 34import android.os.Process; 35import android.os.UserHandle; 36import android.os.UserManager; 37import android.security.KeyStore; 38import android.support.v7.preference.Preference; 39import android.support.v7.preference.PreferenceScreen; 40import android.text.TextUtils; 41import android.util.EventLog; 42import android.util.Log; 43import android.view.View; 44import android.view.accessibility.AccessibilityManager; 45import android.widget.Toast; 46 47import com.android.internal.logging.MetricsProto.MetricsEvent; 48import com.android.internal.widget.LockPatternUtils; 49import com.android.settingslib.RestrictedLockUtils; 50import com.android.settingslib.RestrictedPreference; 51 52import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 53 54public class ChooseLockGeneric extends SettingsActivity { 55 public static final String CONFIRM_CREDENTIALS = "confirm_credentials"; 56 57 @Override 58 public Intent getIntent() { 59 Intent modIntent = new Intent(super.getIntent()); 60 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName()); 61 return modIntent; 62 } 63 64 @Override 65 protected boolean isValidFragment(String fragmentName) { 66 if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true; 67 return false; 68 } 69 70 /* package */ Class<? extends Fragment> getFragmentClass() { 71 return ChooseLockGenericFragment.class; 72 } 73 74 public static class InternalActivity extends ChooseLockGeneric { 75 } 76 77 public static class ChooseLockGenericFragment extends SettingsPreferenceFragment { 78 private static final String TAG = "ChooseLockGenericFragment"; 79 private static final int MIN_PASSWORD_LENGTH = 4; 80 private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off"; 81 private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none"; 82 private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin"; 83 private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password"; 84 private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern"; 85 private static final String PASSWORD_CONFIRMED = "password_confirmed"; 86 private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation"; 87 public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; 88 public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs"; 89 public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality"; 90 public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled"; 91 public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog"; 92 93 private static final int CONFIRM_EXISTING_REQUEST = 100; 94 private static final int ENABLE_ENCRYPTION_REQUEST = 101; 95 private static final int CHOOSE_LOCK_REQUEST = 102; 96 97 private ChooseLockSettingsHelper mChooseLockSettingsHelper; 98 private DevicePolicyManager mDPM; 99 private KeyStore mKeyStore; 100 private boolean mHasChallenge = false; 101 private long mChallenge; 102 private boolean mPasswordConfirmed = false; 103 private boolean mWaitingForConfirmation = false; 104 private int mEncryptionRequestQuality; 105 private boolean mEncryptionRequestDisabled; 106 private boolean mRequirePassword; 107 private boolean mForFingerprint = false; 108 private boolean mForChangeCredRequiredForBoot = false; 109 private String mUserPassword; 110 private LockPatternUtils mLockPatternUtils; 111 private FingerprintManager mFingerprintManager; 112 private int mUserId; 113 private RemovalCallback mRemovalCallback = new RemovalCallback() { 114 115 @Override 116 public void onRemovalSucceeded(Fingerprint fingerprint) { 117 Log.v(TAG, "Fingerprint removed: " + fingerprint.getFingerId()); 118 if (mFingerprintManager.getEnrolledFingerprints().size() == 0) { 119 finish(); 120 } 121 } 122 123 @Override 124 public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { 125 Activity activity = getActivity(); 126 if (activity != null) { 127 Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT); 128 } 129 finish(); 130 } 131 }; 132 133 @Override 134 protected int getMetricsCategory() { 135 return MetricsEvent.CHOOSE_LOCK_GENERIC; 136 } 137 138 @Override 139 public void onCreate(Bundle savedInstanceState) { 140 super.onCreate(savedInstanceState); 141 142 mFingerprintManager = 143 (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE); 144 mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 145 mKeyStore = KeyStore.getInstance(); 146 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); 147 mLockPatternUtils = new LockPatternUtils(getActivity()); 148 149 // Defaults to needing to confirm credentials 150 final boolean confirmCredentials = getActivity().getIntent() 151 .getBooleanExtra(CONFIRM_CREDENTIALS, true); 152 if (getActivity() instanceof ChooseLockGeneric.InternalActivity) { 153 mPasswordConfirmed = !confirmCredentials; 154 } 155 156 mHasChallenge = getActivity().getIntent().getBooleanExtra( 157 ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); 158 mChallenge = getActivity().getIntent().getLongExtra( 159 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); 160 mForFingerprint = getActivity().getIntent().getBooleanExtra( 161 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); 162 mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean( 163 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT); 164 165 if (savedInstanceState != null) { 166 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); 167 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION); 168 mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY); 169 mEncryptionRequestDisabled = savedInstanceState.getBoolean( 170 ENCRYPT_REQUESTED_DISABLED); 171 } 172 173 int targetUser = Utils.getSecureTargetUser( 174 getActivity().getActivityToken(), 175 UserManager.get(getActivity()), 176 null, 177 getActivity().getIntent().getExtras()).getIdentifier(); 178 if (DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals( 179 getActivity().getIntent().getAction()) || 180 !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) { 181 // Always use parent if explicitely requested or if profile challenge is not 182 // supported 183 mUserId = Utils.getUserIdFromBundle(getContext(), getArguments()); 184 } else { 185 mUserId = targetUser; 186 } 187 188 if (mPasswordConfirmed) { 189 updatePreferencesOrFinish(); 190 if (mForChangeCredRequiredForBoot) { 191 maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality( 192 mUserId), false); 193 } 194 } else if (!mWaitingForConfirmation) { 195 ChooseLockSettingsHelper helper = 196 new ChooseLockSettingsHelper(this.getActivity(), this); 197 if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, 198 getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) { 199 mPasswordConfirmed = true; // no password set, so no need to confirm 200 updatePreferencesOrFinish(); 201 } else { 202 mWaitingForConfirmation = true; 203 } 204 } 205 } 206 207 @Override 208 public void onViewCreated(View view, Bundle savedInstanceState) { 209 super.onViewCreated(view, savedInstanceState); 210 if (mForFingerprint) { 211 setHeaderView(R.layout.choose_lock_generic_fingerprint_header); 212 } 213 } 214 215 @Override 216 public boolean onPreferenceTreeClick(Preference preference) { 217 final String key = preference.getKey(); 218 219 if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) { 220 // Show the disabling FRP warning only when the user is switching from a secure 221 // unlock method to an insecure one 222 showFactoryResetProtectionWarningDialog(key); 223 return true; 224 } else { 225 return setUnlockMethod(key); 226 } 227 } 228 229 /** 230 * If the device has encryption already enabled, then ask the user if they 231 * also want to encrypt the phone with this password. 232 * 233 * @param quality 234 * @param disabled 235 */ 236 // TODO: why does this take disabled, its always called with a quality higher than 237 // what makes sense with disabled == true 238 private void maybeEnableEncryption(int quality, boolean disabled) { 239 DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE); 240 if (UserManager.get(getActivity()).isAdminUser() 241 && mUserId == UserHandle.myUserId() 242 && LockPatternUtils.isDeviceEncryptionEnabled() 243 && !LockPatternUtils.isFileEncryptionEnabled() 244 && !dpm.getDoNotAskCredentialsOnBoot()) { 245 mEncryptionRequestQuality = quality; 246 mEncryptionRequestDisabled = disabled; 247 // Get the intent that the encryption interstitial should start for creating 248 // the new unlock method. 249 Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled); 250 unlockMethodIntent.putExtra( 251 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, 252 mForChangeCredRequiredForBoot); 253 final Context context = getActivity(); 254 // If accessibility is enabled and the user hasn't seen this dialog before, set the 255 // default state to agree with that which is compatible with accessibility 256 // (password not required). 257 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled(); 258 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn); 259 Intent intent = getEncryptionInterstitialIntent(context, quality, required, 260 unlockMethodIntent); 261 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, 262 mForFingerprint); 263 startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST); 264 } else { 265 if (mForChangeCredRequiredForBoot) { 266 // Welp, couldn't change it. Oh well. 267 finish(); 268 return; 269 } 270 mRequirePassword = false; // device encryption not enabled or not device owner. 271 updateUnlockMethodAndFinish(quality, disabled); 272 } 273 } 274 275 @Override 276 public void onActivityResult(int requestCode, int resultCode, Intent data) { 277 super.onActivityResult(requestCode, resultCode, data); 278 mWaitingForConfirmation = false; 279 if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) { 280 mPasswordConfirmed = true; 281 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 282 updatePreferencesOrFinish(); 283 if (mForChangeCredRequiredForBoot) { 284 if (!TextUtils.isEmpty(mUserPassword)) { 285 maybeEnableEncryption( 286 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false); 287 } else { 288 finish(); 289 } 290 } 291 } else if (requestCode == CHOOSE_LOCK_REQUEST 292 || requestCode == ENABLE_ENCRYPTION_REQUEST) { 293 if (resultCode != RESULT_CANCELED) { 294 getActivity().setResult(resultCode, data); 295 finish(); 296 } 297 } else { 298 getActivity().setResult(Activity.RESULT_CANCELED); 299 finish(); 300 } 301 if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) { 302 finish(); 303 } 304 } 305 306 @Override 307 public void onSaveInstanceState(Bundle outState) { 308 super.onSaveInstanceState(outState); 309 // Saved so we don't force user to re-enter their password if configuration changes 310 outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed); 311 outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation); 312 outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality); 313 outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled); 314 } 315 316 private void updatePreferencesOrFinish() { 317 Intent intent = getActivity().getIntent(); 318 int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1); 319 if (quality == -1) { 320 // If caller didn't specify password quality, show UI and allow the user to choose. 321 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1); 322 quality = upgradeQuality(quality); 323 final boolean hideDisabledPrefs = intent.getBooleanExtra( 324 HIDE_DISABLED_PREFS, false); 325 final PreferenceScreen prefScreen = getPreferenceScreen(); 326 if (prefScreen != null) { 327 prefScreen.removeAll(); 328 } 329 addPreferencesFromResource(R.xml.security_settings_picker); 330 disableUnusablePreferences(quality, hideDisabledPrefs); 331 updatePreferenceText(); 332 updateCurrentPreference(); 333 updatePreferenceSummaryIfNeeded(); 334 } else { 335 updateUnlockMethodAndFinish(quality, false); 336 } 337 } 338 339 private void updatePreferenceText() { 340 if (mForFingerprint) { 341 Preference pattern = findPreference(KEY_UNLOCK_SET_PATTERN); 342 pattern.setTitle(R.string.fingerprint_unlock_set_unlock_pattern); 343 344 Preference pin = findPreference(KEY_UNLOCK_SET_PIN); 345 pin.setTitle(R.string.fingerprint_unlock_set_unlock_pin); 346 347 Preference password = findPreference(KEY_UNLOCK_SET_PASSWORD); 348 password.setTitle(R.string.fingerprint_unlock_set_unlock_password); 349 } 350 } 351 352 private void updateCurrentPreference() { 353 String currentKey = getKeyForCurrent(); 354 Preference preference = findPreference(currentKey); 355 if (preference != null) { 356 preference.setSummary(R.string.current_screen_lock); 357 } 358 } 359 360 private String getKeyForCurrent() { 361 final int credentialOwner = UserManager.get(getContext()) 362 .getCredentialOwnerProfile(mUserId); 363 if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) { 364 return KEY_UNLOCK_SET_OFF; 365 } 366 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner)) { 367 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 368 return KEY_UNLOCK_SET_PATTERN; 369 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 370 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 371 return KEY_UNLOCK_SET_PIN; 372 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 373 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 374 return KEY_UNLOCK_SET_PASSWORD; 375 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: 376 return KEY_UNLOCK_SET_NONE; 377 } 378 return null; 379 } 380 381 /** increases the quality if necessary */ 382 private int upgradeQuality(int quality) { 383 quality = upgradeQualityForDPM(quality); 384 return quality; 385 } 386 387 private int upgradeQualityForDPM(int quality) { 388 // Compare min allowed password quality 389 int minQuality = mDPM.getPasswordQuality(null); 390 if (quality < minQuality) { 391 quality = minQuality; 392 } 393 return quality; 394 } 395 396 /*** 397 * Disables preferences that are less secure than required quality. The actual 398 * implementation is in disableUnusablePreferenceImpl. 399 * 400 * @param quality the requested quality. 401 * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise 402 * they're not shown at all. 403 */ 404 protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) { 405 disableUnusablePreferencesImpl(quality, hideDisabledPrefs); 406 } 407 408 /*** 409 * Disables preferences that are less secure than required quality. 410 * 411 * @param quality the requested quality. 412 * @param hideDisabled whether to hide disable screen lock options. 413 */ 414 protected void disableUnusablePreferencesImpl(final int quality, 415 boolean hideDisabled) { 416 final PreferenceScreen entries = getPreferenceScreen(); 417 418 int adminEnforcedQuality = mDPM.getPasswordQuality(null); 419 EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet( 420 getActivity(), mUserId); 421 for (int i = entries.getPreferenceCount() - 1; i >= 0; --i) { 422 Preference pref = entries.getPreference(i); 423 if (pref instanceof RestrictedPreference) { 424 final String key = pref.getKey(); 425 boolean enabled = true; 426 boolean visible = true; 427 boolean disabledByAdmin = false; 428 if (KEY_UNLOCK_SET_OFF.equals(key)) { 429 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 430 if (getResources().getBoolean(R.bool.config_hide_none_security_option)) { 431 enabled = false; 432 visible = false; 433 } 434 disabledByAdmin = adminEnforcedQuality 435 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 436 } else if (KEY_UNLOCK_SET_NONE.equals(key)) { 437 if (mUserId != UserHandle.myUserId()) { 438 // Swipe doesn't make sense for profiles. 439 visible = false; 440 } 441 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 442 disabledByAdmin = adminEnforcedQuality 443 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 444 } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) { 445 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 446 disabledByAdmin = adminEnforcedQuality 447 > DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 448 } else if (KEY_UNLOCK_SET_PIN.equals(key)) { 449 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; 450 disabledByAdmin = adminEnforcedQuality 451 > DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; 452 } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) { 453 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 454 disabledByAdmin = adminEnforcedQuality 455 > DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 456 } 457 if (hideDisabled) { 458 visible = enabled; 459 } 460 if (!visible) { 461 entries.removePreference(pref); 462 } else if (disabledByAdmin && enforcedAdmin != null) { 463 ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin); 464 } else if (!enabled) { 465 // we need to setDisabledByAdmin to null first to disable the padlock 466 // in case it was set earlier. 467 ((RestrictedPreference) pref).setDisabledByAdmin(null); 468 pref.setSummary(R.string.unlock_set_unlock_disabled_summary); 469 pref.setEnabled(false); 470 } else { 471 ((RestrictedPreference) pref).setDisabledByAdmin(null); 472 } 473 } 474 } 475 } 476 477 private void updatePreferenceSummaryIfNeeded() { 478 if (LockPatternUtils.isDeviceEncrypted()) { 479 return; 480 } 481 482 if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList( 483 AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) { 484 return; 485 } 486 487 CharSequence summary = getString(R.string.secure_lock_encryption_warning); 488 489 PreferenceScreen screen = getPreferenceScreen(); 490 final int preferenceCount = screen.getPreferenceCount(); 491 for (int i = 0; i < preferenceCount; i++) { 492 Preference preference = screen.getPreference(i); 493 switch (preference.getKey()) { 494 case KEY_UNLOCK_SET_PATTERN: 495 case KEY_UNLOCK_SET_PIN: 496 case KEY_UNLOCK_SET_PASSWORD: { 497 preference.setSummary(summary); 498 } break; 499 } 500 } 501 } 502 503 protected Intent getLockPasswordIntent(Context context, int quality, 504 int minLength, final int maxLength, 505 boolean requirePasswordToDecrypt, boolean confirmCredentials, int userId) { 506 return ChooseLockPassword.createIntent(context, quality, minLength, 507 maxLength, requirePasswordToDecrypt, confirmCredentials, userId); 508 } 509 510 protected Intent getLockPasswordIntent(Context context, int quality, 511 int minLength, final int maxLength, 512 boolean requirePasswordToDecrypt, long challenge, int userId) { 513 return ChooseLockPassword.createIntent(context, quality, minLength, 514 maxLength, requirePasswordToDecrypt, challenge, userId); 515 } 516 517 protected Intent getLockPasswordIntent(Context context, int quality, int minLength, 518 int maxLength, boolean requirePasswordToDecrypt, String password, int userId) { 519 return ChooseLockPassword.createIntent(context, quality, minLength, maxLength, 520 requirePasswordToDecrypt, password, userId); 521 } 522 523 protected Intent getLockPatternIntent(Context context, final boolean requirePassword, 524 final boolean confirmCredentials, int userId) { 525 return ChooseLockPattern.createIntent(context, requirePassword, 526 confirmCredentials, userId); 527 } 528 529 protected Intent getLockPatternIntent(Context context, final boolean requirePassword, 530 long challenge, int userId) { 531 return ChooseLockPattern.createIntent(context, requirePassword, challenge, userId); 532 } 533 534 protected Intent getLockPatternIntent(Context context, final boolean requirePassword, 535 final String pattern, int userId) { 536 return ChooseLockPattern.createIntent(context, requirePassword, pattern, userId); 537 } 538 539 protected Intent getEncryptionInterstitialIntent(Context context, int quality, 540 boolean required, Intent unlockMethodIntent) { 541 return EncryptionInterstitial.createStartIntent(context, quality, required, 542 unlockMethodIntent); 543 } 544 545 /** 546 * Invokes an activity to change the user's pattern, password or PIN based on given quality 547 * and minimum quality specified by DevicePolicyManager. If quality is 548 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared. 549 * 550 * @param quality the desired quality. Ignored if DevicePolicyManager requires more security 551 * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is 552 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED} 553 */ 554 void updateUnlockMethodAndFinish(int quality, boolean disabled) { 555 // Sanity check. We should never get here without confirming user's existing password. 556 if (!mPasswordConfirmed) { 557 throw new IllegalStateException("Tried to update password without confirming it"); 558 } 559 560 quality = upgradeQuality(quality); 561 Intent intent = getIntentForUnlockMethod(quality, disabled); 562 if (intent != null) { 563 startActivityForResult(intent, CHOOSE_LOCK_REQUEST); 564 return; 565 } 566 567 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 568 mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, true); 569 mChooseLockSettingsHelper.utils().clearLock(mUserId); 570 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId); 571 mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, false); 572 removeAllFingerprintTemplatesAndFinish(); 573 getActivity().setResult(Activity.RESULT_OK); 574 } else { 575 removeAllFingerprintTemplatesAndFinish(); 576 } 577 } 578 579 private Intent getIntentForUnlockMethod(int quality, boolean disabled) { 580 Intent intent = null; 581 final Context context = getActivity(); 582 if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { 583 int minLength = mDPM.getPasswordMinimumLength(null); 584 if (minLength < MIN_PASSWORD_LENGTH) { 585 minLength = MIN_PASSWORD_LENGTH; 586 } 587 final int maxLength = mDPM.getPasswordMaximumLength(quality); 588 if (mHasChallenge) { 589 intent = getLockPasswordIntent(context, quality, minLength, 590 maxLength, mRequirePassword, mChallenge, mUserId); 591 } else { 592 intent = getLockPasswordIntent(context, quality, minLength, 593 maxLength, mRequirePassword, mUserPassword, mUserId); 594 } 595 } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { 596 if (mHasChallenge) { 597 intent = getLockPatternIntent(context, mRequirePassword, 598 mChallenge, mUserId); 599 } else { 600 intent = getLockPatternIntent(context, mRequirePassword, 601 mUserPassword, mUserId); 602 } 603 } 604 return intent; 605 } 606 607 private void removeAllFingerprintTemplatesAndFinish() { 608 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected() 609 && mFingerprintManager.getEnrolledFingerprints().size() > 0) { 610 mFingerprintManager.remove( 611 new Fingerprint(null, 0, 0, 0), mUserId, mRemovalCallback); 612 } else { 613 finish(); 614 } 615 } 616 617 @Override 618 public void onDestroy() { 619 super.onDestroy(); 620 } 621 622 @Override 623 protected int getHelpResource() { 624 return R.string.help_url_choose_lockscreen; 625 } 626 627 private int getResIdForFactoryResetProtectionWarningTitle() { 628 boolean isProfile = Utils.isManagedProfile(UserManager.get(getActivity()), mUserId); 629 return isProfile ? R.string.unlock_disable_frp_warning_title_profile 630 : R.string.unlock_disable_frp_warning_title; 631 } 632 633 private int getResIdForFactoryResetProtectionWarningMessage() { 634 boolean hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(); 635 boolean isProfile = Utils.isManagedProfile(UserManager.get(getActivity()), mUserId); 636 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) { 637 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 638 if (hasFingerprints && isProfile) { 639 return R.string 640 .unlock_disable_frp_warning_content_pattern_fingerprint_profile; 641 } else if (hasFingerprints && !isProfile) { 642 return R.string.unlock_disable_frp_warning_content_pattern_fingerprint; 643 } else if (isProfile) { 644 return R.string.unlock_disable_frp_warning_content_pattern_profile; 645 } else { 646 return R.string.unlock_disable_frp_warning_content_pattern; 647 } 648 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 649 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 650 if (hasFingerprints && isProfile) { 651 return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile; 652 } else if (hasFingerprints && !isProfile) { 653 return R.string.unlock_disable_frp_warning_content_pin_fingerprint; 654 } else if (isProfile) { 655 return R.string.unlock_disable_frp_warning_content_pin_profile; 656 } else { 657 return R.string.unlock_disable_frp_warning_content_pin; 658 } 659 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 660 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 661 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 662 if (hasFingerprints && isProfile) { 663 return R.string 664 .unlock_disable_frp_warning_content_password_fingerprint_profile; 665 } else if (hasFingerprints && !isProfile) { 666 return R.string.unlock_disable_frp_warning_content_password_fingerprint; 667 } else if (isProfile) { 668 return R.string.unlock_disable_frp_warning_content_password_profile; 669 } else { 670 return R.string.unlock_disable_frp_warning_content_password; 671 } 672 default: 673 if (hasFingerprints && isProfile) { 674 return R.string 675 .unlock_disable_frp_warning_content_unknown_fingerprint_profile; 676 } else if (hasFingerprints && !isProfile) { 677 return R.string.unlock_disable_frp_warning_content_unknown_fingerprint; 678 } else if (isProfile) { 679 return R.string.unlock_disable_frp_warning_content_unknown_profile; 680 } else { 681 return R.string.unlock_disable_frp_warning_content_unknown; 682 } 683 } 684 } 685 686 private boolean isUnlockMethodSecure(String unlockMethod) { 687 return !(KEY_UNLOCK_SET_OFF.equals(unlockMethod) || 688 KEY_UNLOCK_SET_NONE.equals(unlockMethod)); 689 } 690 691 private boolean setUnlockMethod(String unlockMethod) { 692 EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod); 693 694 if (KEY_UNLOCK_SET_OFF.equals(unlockMethod)) { 695 updateUnlockMethodAndFinish( 696 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true /* disabled */ ); 697 } else if (KEY_UNLOCK_SET_NONE.equals(unlockMethod)) { 698 updateUnlockMethodAndFinish( 699 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false /* disabled */ ); 700 } else if (KEY_UNLOCK_SET_PATTERN.equals(unlockMethod)) { 701 maybeEnableEncryption( 702 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false); 703 } else if (KEY_UNLOCK_SET_PIN.equals(unlockMethod)) { 704 maybeEnableEncryption( 705 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false); 706 } else if (KEY_UNLOCK_SET_PASSWORD.equals(unlockMethod)) { 707 maybeEnableEncryption( 708 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false); 709 } else { 710 Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod); 711 return false; 712 } 713 return true; 714 } 715 716 private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) { 717 int title = getResIdForFactoryResetProtectionWarningTitle(); 718 int message = getResIdForFactoryResetProtectionWarningMessage(); 719 FactoryResetProtectionWarningDialog dialog = 720 FactoryResetProtectionWarningDialog.newInstance( 721 title, message, unlockMethodToSet); 722 dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG); 723 } 724 725 public static class FactoryResetProtectionWarningDialog extends DialogFragment { 726 727 private static final String ARG_TITLE_RES = "titleRes"; 728 private static final String ARG_MESSAGE_RES = "messageRes"; 729 private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet"; 730 731 public static FactoryResetProtectionWarningDialog newInstance( 732 int titleRes, int messageRes, String unlockMethodToSet) { 733 FactoryResetProtectionWarningDialog frag = 734 new FactoryResetProtectionWarningDialog(); 735 Bundle args = new Bundle(); 736 args.putInt(ARG_TITLE_RES, titleRes); 737 args.putInt(ARG_MESSAGE_RES, messageRes); 738 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet); 739 frag.setArguments(args); 740 return frag; 741 } 742 743 @Override 744 public void show(FragmentManager manager, String tag) { 745 if (manager.findFragmentByTag(tag) == null) { 746 // Prevent opening multiple dialogs if tapped on button quickly 747 super.show(manager, tag); 748 } 749 } 750 751 @Override 752 public Dialog onCreateDialog(Bundle savedInstanceState) { 753 final Bundle args = getArguments(); 754 755 return new AlertDialog.Builder(getActivity()) 756 .setTitle(args.getInt(ARG_TITLE_RES)) 757 .setMessage(args.getInt(ARG_MESSAGE_RES)) 758 .setPositiveButton(R.string.unlock_disable_frp_warning_ok, 759 new DialogInterface.OnClickListener() { 760 @Override 761 public void onClick(DialogInterface dialog, int whichButton) { 762 ((ChooseLockGenericFragment) getParentFragment()) 763 .setUnlockMethod( 764 args.getString(ARG_UNLOCK_METHOD_TO_SET)); 765 } 766 } 767 ) 768 .setNegativeButton(R.string.cancel, 769 new DialogInterface.OnClickListener() { 770 @Override 771 public void onClick(DialogInterface dialog, int whichButton) { 772 dismiss(); 773 } 774 } 775 ) 776 .create(); 777 } 778 } 779 } 780} 781