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 17 package com.android.settings.password; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD; 20 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD; 21 22 import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED; 23 24 import android.accessibilityservice.AccessibilityServiceInfo; 25 import android.app.Activity; 26 import android.app.AlertDialog; 27 import android.app.Dialog; 28 import android.app.Fragment; 29 import android.app.FragmentManager; 30 import android.app.admin.DevicePolicyManager; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.pm.UserInfo; 34 import android.hardware.fingerprint.Fingerprint; 35 import android.hardware.fingerprint.FingerprintManager; 36 import android.hardware.fingerprint.FingerprintManager.RemovalCallback; 37 import android.os.Bundle; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.os.storage.StorageManager; 41 import android.security.KeyStore; 42 import android.support.annotation.StringRes; 43 import android.support.v7.preference.Preference; 44 import android.support.v7.preference.PreferenceScreen; 45 import android.text.TextUtils; 46 import android.util.EventLog; 47 import android.util.Log; 48 import android.view.accessibility.AccessibilityManager; 49 import android.widget.TextView; 50 51 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 52 import com.android.internal.widget.LockPatternUtils; 53 import com.android.settings.EncryptionInterstitial; 54 import com.android.settings.EventLogTags; 55 import com.android.settings.R; 56 import com.android.settings.SettingsActivity; 57 import com.android.settings.SettingsPreferenceFragment; 58 import com.android.settings.Utils; 59 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 60 import com.android.settings.fingerprint.FingerprintEnrollBase; 61 import com.android.settings.fingerprint.FingerprintEnrollFindSensor; 62 import com.android.settingslib.RestrictedLockUtils; 63 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 64 import com.android.settingslib.RestrictedPreference; 65 66 import java.util.List; 67 68 public class ChooseLockGeneric extends SettingsActivity { 69 public static final String CONFIRM_CREDENTIALS = "confirm_credentials"; 70 71 @Override 72 public Intent getIntent() { 73 Intent modIntent = new Intent(super.getIntent()); 74 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName()); 75 76 String action = modIntent.getAction(); 77 if (ACTION_SET_NEW_PASSWORD.equals(action) 78 || ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(action)) { 79 modIntent.putExtra(EXTRA_HIDE_DRAWER, true); 80 } 81 return modIntent; 82 } 83 84 @Override 85 protected boolean isValidFragment(String fragmentName) { 86 if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true; 87 return false; 88 } 89 90 /* package */ Class<? extends Fragment> getFragmentClass() { 91 return ChooseLockGenericFragment.class; 92 } 93 94 public static class InternalActivity extends ChooseLockGeneric { 95 } 96 97 public static class ChooseLockGenericFragment extends SettingsPreferenceFragment { 98 99 private static final String TAG = "ChooseLockGenericFragment"; 100 private static final int MIN_PASSWORD_LENGTH = 4; 101 private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint"; 102 private static final String PASSWORD_CONFIRMED = "password_confirmed"; 103 private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation"; 104 public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; 105 public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs"; 106 public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality"; 107 public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled"; 108 public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog"; 109 110 /** 111 * Boolean extra determining whether a "screen lock options" button should be shown. This 112 * extra is both sent and received by ChooseLockGeneric. 113 * 114 * When this extra is false, nothing will be done. 115 * When ChooseLockGeneric receives this extra set as true, and if ChooseLockGeneric is 116 * starting ChooseLockPassword or ChooseLockPattern automatically without user interaction, 117 * ChooseLockGeneric will set this extra to true when starting ChooseLockPassword/Pattern. 118 * 119 * This gives the user the choice to select a different screen lock type, even if 120 * ChooseLockGeneric selected a default. 121 */ 122 public static final String EXTRA_SHOW_OPTIONS_BUTTON = "show_options_button"; 123 124 /** 125 * Original intent extras used to start this activity. This is passed to ChooseLockPassword 126 * when the "screen lock options" button is shown, so that when that button is clicked, 127 * ChooseLockGeneric can be relaunched with the same extras. 128 */ 129 public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras"; 130 131 private static final int CONFIRM_EXISTING_REQUEST = 100; 132 private static final int ENABLE_ENCRYPTION_REQUEST = 101; 133 private static final int CHOOSE_LOCK_REQUEST = 102; 134 private static final int CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST = 103; 135 private static final int SKIP_FINGERPRINT_REQUEST = 104; 136 137 private ChooseLockSettingsHelper mChooseLockSettingsHelper; 138 private DevicePolicyManager mDPM; 139 private KeyStore mKeyStore; 140 private boolean mHasChallenge = false; 141 private long mChallenge; 142 private boolean mPasswordConfirmed = false; 143 private boolean mWaitingForConfirmation = false; 144 private int mEncryptionRequestQuality; 145 private boolean mEncryptionRequestDisabled; 146 private boolean mForChangeCredRequiredForBoot = false; 147 private String mUserPassword; 148 private LockPatternUtils mLockPatternUtils; 149 private FingerprintManager mFingerprintManager; 150 private int mUserId; 151 private boolean mHideDrawer = false; 152 private ManagedLockPasswordProvider mManagedPasswordProvider; 153 private boolean mIsSetNewPassword = false; 154 private UserManager mUserManager; 155 private ChooseLockGenericController mController; 156 157 protected boolean mForFingerprint = false; 158 159 @Override 160 public int getMetricsCategory() { 161 return MetricsEvent.CHOOSE_LOCK_GENERIC; 162 } 163 164 @Override 165 public void onCreate(Bundle savedInstanceState) { 166 super.onCreate(savedInstanceState); 167 168 String chooseLockAction = getActivity().getIntent().getAction(); 169 mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity()); 170 mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 171 mKeyStore = KeyStore.getInstance(); 172 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); 173 mLockPatternUtils = new LockPatternUtils(getActivity()); 174 mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction) 175 || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction); 176 177 // Defaults to needing to confirm credentials 178 final boolean confirmCredentials = getActivity().getIntent() 179 .getBooleanExtra(CONFIRM_CREDENTIALS, true); 180 if (getActivity() instanceof ChooseLockGeneric.InternalActivity) { 181 mPasswordConfirmed = !confirmCredentials; 182 mUserPassword = getActivity().getIntent().getStringExtra( 183 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 184 } 185 mHideDrawer = getActivity().getIntent().getBooleanExtra(EXTRA_HIDE_DRAWER, false); 186 187 mHasChallenge = getActivity().getIntent().getBooleanExtra( 188 ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); 189 mChallenge = getActivity().getIntent().getLongExtra( 190 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); 191 mForFingerprint = getActivity().getIntent().getBooleanExtra( 192 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); 193 mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean( 194 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT); 195 mUserManager = UserManager.get(getActivity()); 196 197 if (savedInstanceState != null) { 198 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); 199 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION); 200 mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY); 201 mEncryptionRequestDisabled = savedInstanceState.getBoolean( 202 ENCRYPT_REQUESTED_DISABLED); 203 if (mUserPassword == null) { 204 mUserPassword = savedInstanceState.getString( 205 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 206 } 207 } 208 209 // a) If this is started from other user, use that user id. 210 // b) If this is started from the same user, read the extra if this is launched 211 // from Settings app itself. 212 // c) Otherwise, use UserHandle.myUserId(). 213 mUserId = Utils.getSecureTargetUser( 214 getActivity().getActivityToken(), 215 UserManager.get(getActivity()), 216 getArguments(), 217 getActivity().getIntent().getExtras()).getIdentifier(); 218 mController = new ChooseLockGenericController(getContext(), mUserId); 219 if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction) 220 && UserManager.get(getActivity()).isManagedProfile(mUserId) 221 && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) { 222 getActivity().setTitle(R.string.lock_settings_picker_title_profile); 223 } 224 225 mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId); 226 227 if (mPasswordConfirmed) { 228 updatePreferencesOrFinish(savedInstanceState != null); 229 if (mForChangeCredRequiredForBoot) { 230 maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality( 231 mUserId), false); 232 } 233 } else if (!mWaitingForConfirmation) { 234 ChooseLockSettingsHelper helper = 235 new ChooseLockSettingsHelper(this.getActivity(), this); 236 boolean managedProfileWithUnifiedLock = 237 UserManager.get(getActivity()).isManagedProfile(mUserId) 238 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId); 239 boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword; 240 if (skipConfirmation 241 || !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, 242 getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) { 243 mPasswordConfirmed = true; // no password set, so no need to confirm 244 updatePreferencesOrFinish(savedInstanceState != null); 245 } else { 246 mWaitingForConfirmation = true; 247 } 248 } 249 addHeaderView(); 250 } 251 252 protected void addHeaderView() { 253 if (mForFingerprint) { 254 setHeaderView(R.layout.choose_lock_generic_fingerprint_header); 255 if (mIsSetNewPassword) { 256 ((TextView) getHeaderView().findViewById(R.id.fingerprint_header_description)) 257 .setText(R.string.fingerprint_unlock_title); 258 } 259 } 260 } 261 262 @Override 263 public boolean onPreferenceTreeClick(Preference preference) { 264 final String key = preference.getKey(); 265 266 if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) { 267 // Show the disabling FRP warning only when the user is switching from a secure 268 // unlock method to an insecure one 269 showFactoryResetProtectionWarningDialog(key); 270 return true; 271 } else if (KEY_SKIP_FINGERPRINT.equals(key)) { 272 Intent chooseLockGenericIntent = new Intent(getActivity(), 273 ChooseLockGeneric.InternalActivity.class); 274 chooseLockGenericIntent.setAction(getIntent().getAction()); 275 // Forward the target user id to ChooseLockGeneric. 276 chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId); 277 chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed); 278 if (mUserPassword != null) { 279 chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, 280 mUserPassword); 281 } 282 startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST); 283 return true; 284 } else { 285 return setUnlockMethod(key); 286 } 287 } 288 289 /** 290 * If the device has encryption already enabled, then ask the user if they 291 * also want to encrypt the phone with this password. 292 * 293 * @param quality 294 * @param disabled 295 */ 296 // TODO: why does this take disabled, its always called with a quality higher than 297 // what makes sense with disabled == true 298 private void maybeEnableEncryption(int quality, boolean disabled) { 299 DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE); 300 if (UserManager.get(getActivity()).isAdminUser() 301 && mUserId == UserHandle.myUserId() 302 && LockPatternUtils.isDeviceEncryptionEnabled() 303 && !LockPatternUtils.isFileEncryptionEnabled() 304 && !dpm.getDoNotAskCredentialsOnBoot()) { 305 mEncryptionRequestQuality = quality; 306 mEncryptionRequestDisabled = disabled; 307 // Get the intent that the encryption interstitial should start for creating 308 // the new unlock method. 309 Intent unlockMethodIntent = getIntentForUnlockMethod(quality); 310 unlockMethodIntent.putExtra( 311 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, 312 mForChangeCredRequiredForBoot); 313 final Context context = getActivity(); 314 // If accessibility is enabled and the user hasn't seen this dialog before, set the 315 // default state to agree with that which is compatible with accessibility 316 // (password not required). 317 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled(); 318 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn); 319 Intent intent = getEncryptionInterstitialIntent(context, quality, required, 320 unlockMethodIntent); 321 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, 322 mForFingerprint); 323 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer); 324 startActivityForResult( 325 intent, 326 mIsSetNewPassword && mHasChallenge 327 ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST 328 : ENABLE_ENCRYPTION_REQUEST); 329 } else { 330 if (mForChangeCredRequiredForBoot) { 331 // Welp, couldn't change it. Oh well. 332 finish(); 333 return; 334 } 335 updateUnlockMethodAndFinish(quality, disabled, false /* chooseLockSkipped */); 336 } 337 } 338 339 @Override 340 public void onActivityResult(int requestCode, int resultCode, Intent data) { 341 super.onActivityResult(requestCode, resultCode, data); 342 mWaitingForConfirmation = false; 343 if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) { 344 mPasswordConfirmed = true; 345 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 346 updatePreferencesOrFinish(false /* isRecreatingActivity */); 347 if (mForChangeCredRequiredForBoot) { 348 if (!TextUtils.isEmpty(mUserPassword)) { 349 maybeEnableEncryption( 350 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false); 351 } else { 352 finish(); 353 } 354 } 355 } else if (requestCode == CHOOSE_LOCK_REQUEST 356 || requestCode == ENABLE_ENCRYPTION_REQUEST) { 357 if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) { 358 getActivity().setResult(resultCode, data); 359 finish(); 360 } else { 361 // If PASSWORD_TYPE_KEY is set, this activity is used as a trampoline to start 362 // the actual password enrollment. If the result is canceled, which means the 363 // user pressed back, finish the activity with result canceled. 364 int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1); 365 if (quality != -1) { 366 getActivity().setResult(RESULT_CANCELED, data); 367 finish(); 368 } 369 } 370 } else if (requestCode == CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST 371 && resultCode == FingerprintEnrollBase.RESULT_FINISHED) { 372 Intent intent = getFindSensorIntent(getActivity()); 373 if (data != null) { 374 intent.putExtras(data.getExtras()); 375 } 376 // Forward the target user id to fingerprint setup page. 377 intent.putExtra(Intent.EXTRA_USER_ID, mUserId); 378 startActivity(intent); 379 finish(); 380 } else if (requestCode == SKIP_FINGERPRINT_REQUEST) { 381 if (resultCode != RESULT_CANCELED) { 382 getActivity().setResult( 383 resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data); 384 finish(); 385 } 386 } else { 387 getActivity().setResult(Activity.RESULT_CANCELED); 388 finish(); 389 } 390 if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) { 391 finish(); 392 } 393 } 394 395 protected Intent getFindSensorIntent(Context context) { 396 return new Intent(context, FingerprintEnrollFindSensor.class); 397 } 398 399 @Override 400 public void onSaveInstanceState(Bundle outState) { 401 super.onSaveInstanceState(outState); 402 // Saved so we don't force user to re-enter their password if configuration changes 403 outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed); 404 outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation); 405 outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality); 406 outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled); 407 if (mUserPassword != null) { 408 outState.putString(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword); 409 } 410 } 411 412 private void updatePreferencesOrFinish(boolean isRecreatingActivity) { 413 Intent intent = getActivity().getIntent(); 414 int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1); 415 if (quality == -1) { 416 // If caller didn't specify password quality, show UI and allow the user to choose. 417 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1); 418 quality = mController.upgradeQuality(quality); 419 final boolean hideDisabledPrefs = intent.getBooleanExtra( 420 HIDE_DISABLED_PREFS, false); 421 final PreferenceScreen prefScreen = getPreferenceScreen(); 422 if (prefScreen != null) { 423 prefScreen.removeAll(); 424 } 425 addPreferences(); 426 disableUnusablePreferences(quality, hideDisabledPrefs); 427 updatePreferenceText(); 428 updateCurrentPreference(); 429 updatePreferenceSummaryIfNeeded(); 430 } else if (!isRecreatingActivity) { 431 // Don't start the activity again if we are recreated for configuration change 432 updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */); 433 } 434 } 435 436 protected void addPreferences() { 437 addPreferencesFromResource(R.xml.security_settings_picker); 438 439 // Used for testing purposes 440 findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none); 441 findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none); 442 findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin); 443 findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password); 444 } 445 446 private void updatePreferenceText() { 447 if (mForFingerprint) { 448 setPreferenceTitle(ScreenLockType.PATTERN, 449 R.string.fingerprint_unlock_set_unlock_pattern); 450 setPreferenceTitle(ScreenLockType.PIN, R.string.fingerprint_unlock_set_unlock_pin); 451 setPreferenceTitle(ScreenLockType.PASSWORD, 452 R.string.fingerprint_unlock_set_unlock_password); 453 } 454 455 if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) { 456 setPreferenceTitle(ScreenLockType.MANAGED, 457 mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint)); 458 } else { 459 removePreference(ScreenLockType.MANAGED.preferenceKey); 460 } 461 462 if (!(mForFingerprint && mIsSetNewPassword)) { 463 removePreference(KEY_SKIP_FINGERPRINT); 464 } 465 } 466 467 private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) { 468 Preference preference = findPreference(lock.preferenceKey); 469 if (preference != null) { 470 preference.setTitle(title); 471 } 472 } 473 474 private void setPreferenceTitle(ScreenLockType lock, CharSequence title) { 475 Preference preference = findPreference(lock.preferenceKey); 476 if (preference != null) { 477 preference.setTitle(title); 478 } 479 } 480 481 private void setPreferenceSummary(ScreenLockType lock, @StringRes int summary) { 482 Preference preference = findPreference(lock.preferenceKey); 483 if (preference != null) { 484 preference.setSummary(summary); 485 } 486 } 487 488 private void updateCurrentPreference() { 489 String currentKey = getKeyForCurrent(); 490 Preference preference = findPreference(currentKey); 491 if (preference != null) { 492 preference.setSummary(R.string.current_screen_lock); 493 } 494 } 495 496 private String getKeyForCurrent() { 497 final int credentialOwner = UserManager.get(getContext()) 498 .getCredentialOwnerProfile(mUserId); 499 if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) { 500 return ScreenLockType.NONE.preferenceKey; 501 } 502 ScreenLockType lock = 503 ScreenLockType.fromQuality( 504 mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner)); 505 return lock != null ? lock.preferenceKey : null; 506 } 507 508 /*** 509 * Disables preferences that are less secure than required quality. The actual 510 * implementation is in disableUnusablePreferenceImpl. 511 * 512 * @param quality the requested quality. 513 * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise 514 * they're not shown at all. 515 */ 516 protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) { 517 disableUnusablePreferencesImpl(quality, hideDisabledPrefs); 518 } 519 520 /*** 521 * Disables preferences that are less secure than required quality. 522 * 523 * @param quality the requested quality. 524 * @param hideDisabled whether to hide disable screen lock options. 525 */ 526 protected void disableUnusablePreferencesImpl(final int quality, 527 boolean hideDisabled) { 528 final PreferenceScreen entries = getPreferenceScreen(); 529 530 int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId); 531 EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet( 532 getActivity(), mUserId); 533 534 for (ScreenLockType lock : ScreenLockType.values()) { 535 String key = lock.preferenceKey; 536 Preference pref = findPreference(key); 537 if (pref instanceof RestrictedPreference) { 538 boolean visible = mController.isScreenLockVisible(lock); 539 boolean enabled = mController.isScreenLockEnabled(lock, quality); 540 boolean disabledByAdmin = 541 mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality); 542 if (hideDisabled) { 543 visible = visible && enabled; 544 } 545 if (!visible) { 546 entries.removePreference(pref); 547 } else if (disabledByAdmin && enforcedAdmin != null) { 548 ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin); 549 } else if (!enabled) { 550 // we need to setDisabledByAdmin to null first to disable the padlock 551 // in case it was set earlier. 552 ((RestrictedPreference) pref).setDisabledByAdmin(null); 553 pref.setSummary(R.string.unlock_set_unlock_disabled_summary); 554 pref.setEnabled(false); 555 } else { 556 ((RestrictedPreference) pref).setDisabledByAdmin(null); 557 } 558 } 559 } 560 } 561 562 private void updatePreferenceSummaryIfNeeded() { 563 // On a default block encrypted device with accessibility, add a warning 564 // that your data is not credential encrypted 565 if (!StorageManager.isBlockEncrypted()) { 566 return; 567 } 568 569 if (StorageManager.isNonDefaultBlockEncrypted()) { 570 return; 571 } 572 573 if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList( 574 AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) { 575 return; 576 } 577 578 setPreferenceSummary(ScreenLockType.PATTERN, R.string.secure_lock_encryption_warning); 579 setPreferenceSummary(ScreenLockType.PIN, R.string.secure_lock_encryption_warning); 580 setPreferenceSummary(ScreenLockType.PASSWORD, R.string.secure_lock_encryption_warning); 581 setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning); 582 } 583 584 protected Intent getLockManagedPasswordIntent(String password) { 585 return mManagedPasswordProvider.createIntent(false, password); 586 } 587 588 protected Intent getLockPasswordIntent(int quality, int minLength, int maxLength) { 589 ChooseLockPassword.IntentBuilder builder = 590 new ChooseLockPassword.IntentBuilder(getContext()) 591 .setPasswordQuality(quality) 592 .setPasswordLengthRange(minLength, maxLength) 593 .setForFingerprint(mForFingerprint) 594 .setUserId(mUserId); 595 if (mHasChallenge) { 596 builder.setChallenge(mChallenge); 597 } 598 if (mUserPassword != null) { 599 builder.setPassword(mUserPassword); 600 } 601 return builder.build(); 602 } 603 604 protected Intent getLockPatternIntent() { 605 ChooseLockPattern.IntentBuilder builder = 606 new ChooseLockPattern.IntentBuilder(getContext()) 607 .setForFingerprint(mForFingerprint) 608 .setUserId(mUserId); 609 if (mHasChallenge) { 610 builder.setChallenge(mChallenge); 611 } 612 if (mUserPassword != null) { 613 builder.setPattern(mUserPassword); 614 } 615 return builder.build(); 616 } 617 618 protected Intent getEncryptionInterstitialIntent(Context context, int quality, 619 boolean required, Intent unlockMethodIntent) { 620 return EncryptionInterstitial.createStartIntent(context, quality, required, 621 unlockMethodIntent); 622 } 623 624 /** 625 * Invokes an activity to change the user's pattern, password or PIN based on given quality 626 * and minimum quality specified by DevicePolicyManager. If quality is 627 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared. 628 * 629 * @param quality the desired quality. Ignored if DevicePolicyManager requires more security 630 * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is 631 * @param chooseLockSkipped whether or not this activity is skipped. This is true when this 632 * activity was not shown to the user at all, instead automatically proceeding based on 633 * the given intent extras, typically {@link LockPatternUtils#PASSWORD_TYPE_KEY}. 634 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED} 635 */ 636 void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) { 637 // Sanity check. We should never get here without confirming user's existing password. 638 if (!mPasswordConfirmed) { 639 throw new IllegalStateException("Tried to update password without confirming it"); 640 } 641 642 quality = mController.upgradeQuality(quality); 643 Intent intent = getIntentForUnlockMethod(quality); 644 if (intent != null) { 645 if (getIntent().getBooleanExtra(EXTRA_SHOW_OPTIONS_BUTTON, false)) { 646 intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped); 647 } 648 intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras()); 649 startActivityForResult(intent, 650 mIsSetNewPassword && mHasChallenge 651 ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST 652 : CHOOSE_LOCK_REQUEST); 653 return; 654 } 655 656 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 657 mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId); 658 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId); 659 getActivity().setResult(Activity.RESULT_OK); 660 removeAllFingerprintForUserAndFinish(mUserId); 661 } else { 662 removeAllFingerprintForUserAndFinish(mUserId); 663 } 664 } 665 666 private Intent getIntentForUnlockMethod(int quality) { 667 Intent intent = null; 668 if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { 669 intent = getLockManagedPasswordIntent(mUserPassword); 670 } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { 671 int minLength = mDPM.getPasswordMinimumLength(null, mUserId); 672 if (minLength < MIN_PASSWORD_LENGTH) { 673 minLength = MIN_PASSWORD_LENGTH; 674 } 675 final int maxLength = mDPM.getPasswordMaximumLength(quality); 676 intent = getLockPasswordIntent(quality, minLength, maxLength); 677 } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { 678 intent = getLockPatternIntent(); 679 } 680 if (intent != null) { 681 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer); 682 } 683 return intent; 684 } 685 686 private void removeAllFingerprintForUserAndFinish(final int userId) { 687 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { 688 if (mFingerprintManager.hasEnrolledFingerprints(userId)) { 689 mFingerprintManager.setActiveUser(userId); 690 // For the purposes of M and N, groupId is the same as userId. 691 final int groupId = userId; 692 Fingerprint finger = new Fingerprint(null, groupId, 0, 0); 693 mFingerprintManager.remove(finger, userId, 694 new RemovalCallback() { 695 @Override 696 public void onRemovalError(Fingerprint fp, int errMsgId, 697 CharSequence errString) { 698 Log.e(TAG, String.format( 699 "Can't remove fingerprint %d in group %d. Reason: %s", 700 fp.getFingerId(), fp.getGroupId(), errString)); 701 // TODO: need to proceed with the removal of managed profile 702 // fingerprints and finish() gracefully. 703 } 704 705 @Override 706 public void onRemovalSucceeded(Fingerprint fp, int remaining) { 707 if (remaining == 0) { 708 removeManagedProfileFingerprintsAndFinishIfNecessary(userId); 709 } 710 } 711 }); 712 } else { 713 // No fingerprints in this user, we may also want to delete managed profile 714 // fingerprints 715 removeManagedProfileFingerprintsAndFinishIfNecessary(userId); 716 } 717 } else { 718 // The removal callback will call finish, once all fingerprints are removed. 719 // We need to wait for that to occur, otherwise, the UI will still show that 720 // fingerprints exist even though they are (about to) be removed depending on 721 // the race condition. 722 finish(); 723 } 724 } 725 726 private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId) { 727 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { 728 mFingerprintManager.setActiveUser(UserHandle.myUserId()); 729 } 730 boolean hasChildProfile = false; 731 if (!mUserManager.getUserInfo(parentUserId).isManagedProfile()) { 732 // Current user is primary profile, remove work profile fingerprints if necessary 733 final List<UserInfo> profiles = mUserManager.getProfiles(parentUserId); 734 final int profilesSize = profiles.size(); 735 for (int i = 0; i < profilesSize; i++) { 736 final UserInfo userInfo = profiles.get(i); 737 if (userInfo.isManagedProfile() && !mLockPatternUtils 738 .isSeparateProfileChallengeEnabled(userInfo.id)) { 739 removeAllFingerprintForUserAndFinish(userInfo.id); 740 hasChildProfile = true; 741 break; 742 } 743 } 744 } 745 if (!hasChildProfile) { 746 finish(); 747 } 748 } 749 750 @Override 751 public void onDestroy() { 752 super.onDestroy(); 753 } 754 755 @Override 756 public int getHelpResource() { 757 return R.string.help_url_choose_lockscreen; 758 } 759 760 private int getResIdForFactoryResetProtectionWarningTitle() { 761 boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId); 762 return isProfile ? R.string.unlock_disable_frp_warning_title_profile 763 : R.string.unlock_disable_frp_warning_title; 764 } 765 766 private int getResIdForFactoryResetProtectionWarningMessage() { 767 final boolean hasFingerprints; 768 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { 769 hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(mUserId); 770 } else { 771 hasFingerprints = false; 772 } 773 boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId); 774 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) { 775 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 776 if (hasFingerprints && isProfile) { 777 return R.string 778 .unlock_disable_frp_warning_content_pattern_fingerprint_profile; 779 } else if (hasFingerprints && !isProfile) { 780 return R.string.unlock_disable_frp_warning_content_pattern_fingerprint; 781 } else if (isProfile) { 782 return R.string.unlock_disable_frp_warning_content_pattern_profile; 783 } else { 784 return R.string.unlock_disable_frp_warning_content_pattern; 785 } 786 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 787 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 788 if (hasFingerprints && isProfile) { 789 return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile; 790 } else if (hasFingerprints && !isProfile) { 791 return R.string.unlock_disable_frp_warning_content_pin_fingerprint; 792 } else if (isProfile) { 793 return R.string.unlock_disable_frp_warning_content_pin_profile; 794 } else { 795 return R.string.unlock_disable_frp_warning_content_pin; 796 } 797 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 798 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 799 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 800 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: 801 if (hasFingerprints && isProfile) { 802 return R.string 803 .unlock_disable_frp_warning_content_password_fingerprint_profile; 804 } else if (hasFingerprints && !isProfile) { 805 return R.string.unlock_disable_frp_warning_content_password_fingerprint; 806 } else if (isProfile) { 807 return R.string.unlock_disable_frp_warning_content_password_profile; 808 } else { 809 return R.string.unlock_disable_frp_warning_content_password; 810 } 811 default: 812 if (hasFingerprints && isProfile) { 813 return R.string 814 .unlock_disable_frp_warning_content_unknown_fingerprint_profile; 815 } else if (hasFingerprints && !isProfile) { 816 return R.string.unlock_disable_frp_warning_content_unknown_fingerprint; 817 } else if (isProfile) { 818 return R.string.unlock_disable_frp_warning_content_unknown_profile; 819 } else { 820 return R.string.unlock_disable_frp_warning_content_unknown; 821 } 822 } 823 } 824 825 private boolean isUnlockMethodSecure(String unlockMethod) { 826 return !(ScreenLockType.SWIPE.preferenceKey.equals(unlockMethod) || 827 ScreenLockType.NONE.preferenceKey.equals(unlockMethod)); 828 } 829 830 private boolean setUnlockMethod(String unlockMethod) { 831 EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod); 832 833 ScreenLockType lock = ScreenLockType.fromKey(unlockMethod); 834 if (lock != null) { 835 switch (lock) { 836 case NONE: 837 case SWIPE: 838 updateUnlockMethodAndFinish( 839 lock.defaultQuality, 840 lock == ScreenLockType.NONE, 841 false /* chooseLockSkipped */); 842 return true; 843 case PATTERN: 844 case PIN: 845 case PASSWORD: 846 case MANAGED: 847 maybeEnableEncryption(lock.defaultQuality, false); 848 return true; 849 } 850 } 851 Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod); 852 return false; 853 } 854 855 private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) { 856 int title = getResIdForFactoryResetProtectionWarningTitle(); 857 int message = getResIdForFactoryResetProtectionWarningMessage(); 858 FactoryResetProtectionWarningDialog dialog = 859 FactoryResetProtectionWarningDialog.newInstance( 860 title, message, unlockMethodToSet); 861 dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG); 862 } 863 864 public static class FactoryResetProtectionWarningDialog extends InstrumentedDialogFragment { 865 866 private static final String ARG_TITLE_RES = "titleRes"; 867 private static final String ARG_MESSAGE_RES = "messageRes"; 868 private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet"; 869 870 public static FactoryResetProtectionWarningDialog newInstance( 871 int titleRes, int messageRes, String unlockMethodToSet) { 872 FactoryResetProtectionWarningDialog frag = 873 new FactoryResetProtectionWarningDialog(); 874 Bundle args = new Bundle(); 875 args.putInt(ARG_TITLE_RES, titleRes); 876 args.putInt(ARG_MESSAGE_RES, messageRes); 877 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet); 878 frag.setArguments(args); 879 return frag; 880 } 881 882 @Override 883 public void show(FragmentManager manager, String tag) { 884 if (manager.findFragmentByTag(tag) == null) { 885 // Prevent opening multiple dialogs if tapped on button quickly 886 super.show(manager, tag); 887 } 888 } 889 890 @Override 891 public Dialog onCreateDialog(Bundle savedInstanceState) { 892 final Bundle args = getArguments(); 893 894 return new AlertDialog.Builder(getActivity()) 895 .setTitle(args.getInt(ARG_TITLE_RES)) 896 .setMessage(args.getInt(ARG_MESSAGE_RES)) 897 .setPositiveButton(R.string.unlock_disable_frp_warning_ok, 898 (dialog, whichButton) -> { 899 String unlockMethod = args.getString(ARG_UNLOCK_METHOD_TO_SET); 900 ((ChooseLockGenericFragment) getParentFragment()) 901 .setUnlockMethod(unlockMethod); 902 }) 903 .setNegativeButton(R.string.cancel, (dialog, whichButton) -> dismiss()) 904 .create(); 905 } 906 907 @Override 908 public int getMetricsCategory() { 909 return MetricsEvent.DIALOG_FRP; 910 } 911 } 912 } 913 } 914