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