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