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