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