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