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.PASSWORD_COMPLEXITY_NONE; 20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 21 import static android.app.admin.DevicePolicyResources.Strings.Settings.PASSWORD_RECENTLY_USED; 22 import static android.app.admin.DevicePolicyResources.Strings.Settings.PIN_RECENTLY_USED; 23 import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PASSWORD_HEADER; 24 import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PIN_HEADER; 25 import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PASSWORD_HEADER; 26 import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PIN_HEADER; 27 import static android.app.admin.DevicePolicyResources.UNDEFINED; 28 import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; 29 30 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; 31 import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS; 32 import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE; 33 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS; 34 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LETTERS; 35 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LOWER_CASE; 36 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_DIGITS; 37 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_LETTER; 38 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_SYMBOLS; 39 import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE; 40 import static com.android.internal.widget.PasswordValidationError.RECENTLY_USED; 41 import static com.android.internal.widget.PasswordValidationError.TOO_LONG; 42 import static com.android.internal.widget.PasswordValidationError.TOO_SHORT; 43 import static com.android.internal.widget.PasswordValidationError.TOO_SHORT_WHEN_ALL_NUMERIC; 44 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL; 45 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; 46 47 import android.app.Activity; 48 import android.app.admin.DevicePolicyManager; 49 import android.app.admin.DevicePolicyManager.PasswordComplexity; 50 import android.app.admin.PasswordMetrics; 51 import android.app.settings.SettingsEnums; 52 import android.content.Context; 53 import android.content.Intent; 54 import android.graphics.Insets; 55 import android.graphics.Typeface; 56 import android.os.Bundle; 57 import android.os.Handler; 58 import android.os.Message; 59 import android.os.UserHandle; 60 import android.os.UserManager; 61 import android.text.Editable; 62 import android.text.InputType; 63 import android.text.Selection; 64 import android.text.Spannable; 65 import android.text.TextUtils; 66 import android.text.TextWatcher; 67 import android.util.Log; 68 import android.view.KeyEvent; 69 import android.view.LayoutInflater; 70 import android.view.View; 71 import android.view.ViewGroup; 72 import android.view.WindowManager; 73 import android.view.inputmethod.EditorInfo; 74 import android.widget.CheckBox; 75 import android.widget.ImeAwareEditText; 76 import android.widget.LinearLayout; 77 import android.widget.TextView; 78 import android.widget.TextView.OnEditorActionListener; 79 80 import androidx.annotation.Nullable; 81 import androidx.annotation.StringRes; 82 import androidx.fragment.app.Fragment; 83 import androidx.recyclerview.widget.LinearLayoutManager; 84 import androidx.recyclerview.widget.RecyclerView; 85 86 import com.android.internal.annotations.VisibleForTesting; 87 import com.android.internal.widget.LockPatternUtils; 88 import com.android.internal.widget.LockscreenCredential; 89 import com.android.internal.widget.PasswordValidationError; 90 import com.android.internal.widget.TextViewInputDisabler; 91 import com.android.settings.R; 92 import com.android.settings.SettingsActivity; 93 import com.android.settings.SetupWizardUtils; 94 import com.android.settings.Utils; 95 import com.android.settings.core.InstrumentedFragment; 96 import com.android.settings.notification.RedactionInterstitial; 97 import com.android.settingslib.utils.StringUtil; 98 99 import com.google.android.setupcompat.template.FooterBarMixin; 100 import com.google.android.setupcompat.template.FooterButton; 101 import com.google.android.setupdesign.GlifLayout; 102 import com.google.android.setupdesign.util.ThemeHelper; 103 104 import java.util.ArrayList; 105 import java.util.Collections; 106 import java.util.HashMap; 107 import java.util.List; 108 import java.util.Map; 109 110 public class ChooseLockPassword extends SettingsActivity { 111 private static final String TAG = "ChooseLockPassword"; 112 113 static final String EXTRA_KEY_MIN_METRICS = "min_metrics"; 114 static final String EXTRA_KEY_MIN_COMPLEXITY = "min_complexity"; 115 116 @Override getIntent()117 public Intent getIntent() { 118 Intent modIntent = new Intent(super.getIntent()); 119 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName()); 120 return modIntent; 121 } 122 123 public static class IntentBuilder { 124 125 private final Intent mIntent; 126 IntentBuilder(Context context)127 public IntentBuilder(Context context) { 128 mIntent = new Intent(context, ChooseLockPassword.class); 129 mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false); 130 } 131 132 /** 133 * Sets the intended credential type i.e. whether it's numeric PIN or general password 134 * @param passwordType password type represented by one of the {@code PASSWORD_QUALITY_} 135 * constants. 136 */ setPasswordType(int passwordType)137 public IntentBuilder setPasswordType(int passwordType) { 138 mIntent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, passwordType); 139 return this; 140 } 141 setUserId(int userId)142 public IntentBuilder setUserId(int userId) { 143 mIntent.putExtra(Intent.EXTRA_USER_ID, userId); 144 return this; 145 } 146 setRequestGatekeeperPasswordHandle( boolean requestGatekeeperPasswordHandle)147 public IntentBuilder setRequestGatekeeperPasswordHandle( 148 boolean requestGatekeeperPasswordHandle) { 149 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, 150 requestGatekeeperPasswordHandle); 151 return this; 152 } 153 setPassword(LockscreenCredential password)154 public IntentBuilder setPassword(LockscreenCredential password) { 155 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, password); 156 return this; 157 } 158 setForFingerprint(boolean forFingerprint)159 public IntentBuilder setForFingerprint(boolean forFingerprint) { 160 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint); 161 return this; 162 } 163 setForFace(boolean forFace)164 public IntentBuilder setForFace(boolean forFace) { 165 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace); 166 return this; 167 } 168 setForBiometrics(boolean forBiometrics)169 public IntentBuilder setForBiometrics(boolean forBiometrics) { 170 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics); 171 return this; 172 } 173 174 /** Sets the minimum password requirement in terms of complexity and metrics */ setPasswordRequirement(@asswordComplexity int level, PasswordMetrics metrics)175 public IntentBuilder setPasswordRequirement(@PasswordComplexity int level, 176 PasswordMetrics metrics) { 177 mIntent.putExtra(EXTRA_KEY_MIN_COMPLEXITY, level); 178 mIntent.putExtra(EXTRA_KEY_MIN_METRICS, metrics); 179 return this; 180 } 181 182 /** 183 * Configures the launch such that at the end of the password enrollment, one of its 184 * managed profile (specified by {@code profileId}) will have its lockscreen unified 185 * to the parent user. The profile's current lockscreen credential needs to be specified by 186 * {@code credential}. 187 */ setProfileToUnify(int profileId, LockscreenCredential credential)188 public IntentBuilder setProfileToUnify(int profileId, LockscreenCredential credential) { 189 mIntent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, profileId); 190 mIntent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, credential); 191 return this; 192 } 193 build()194 public Intent build() { 195 return mIntent; 196 } 197 } 198 199 @Override isValidFragment(String fragmentName)200 protected boolean isValidFragment(String fragmentName) { 201 if (ChooseLockPasswordFragment.class.getName().equals(fragmentName)) return true; 202 return false; 203 } 204 205 @Override isToolbarEnabled()206 protected boolean isToolbarEnabled() { 207 return false; 208 } 209 getFragmentClass()210 /* package */ Class<? extends Fragment> getFragmentClass() { 211 return ChooseLockPasswordFragment.class; 212 } 213 214 @Override onCreate(Bundle savedInstanceState)215 protected void onCreate(Bundle savedInstanceState) { 216 setTheme(SetupWizardUtils.getTheme(this, getIntent())); 217 ThemeHelper.trySetDynamicColor(this); 218 super.onCreate(savedInstanceState); 219 findViewById(R.id.content_parent).setFitsSystemWindows(false); 220 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); 221 } 222 223 public static class ChooseLockPasswordFragment extends InstrumentedFragment 224 implements OnEditorActionListener, TextWatcher, SaveAndFinishWorker.Listener { 225 private static final String KEY_FIRST_PASSWORD = "first_password"; 226 private static final String KEY_UI_STAGE = "ui_stage"; 227 private static final String KEY_CURRENT_CREDENTIAL = "current_credential"; 228 private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker"; 229 private static final String KEY_IS_AUTO_CONFIRM_CHECK_MANUALLY_CHANGED = 230 "auto_confirm_option_set_manually"; 231 232 private static final int MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6; 233 234 private LockscreenCredential mCurrentCredential; 235 private LockscreenCredential mChosenPassword; 236 private boolean mRequestGatekeeperPassword; 237 private boolean mRequestWriteRepairModePassword; 238 private ImeAwareEditText mPasswordEntry; 239 private TextViewInputDisabler mPasswordEntryInputDisabler; 240 241 // Minimum password metrics enforced by admins. 242 private PasswordMetrics mMinMetrics; 243 private List<PasswordValidationError> mValidationErrors; 244 245 @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE; 246 protected int mUserId; 247 private byte[] mPasswordHistoryHashFactor; 248 private int mUnificationProfileId = UserHandle.USER_NULL; 249 250 private LockPatternUtils mLockPatternUtils; 251 private SaveAndFinishWorker mSaveAndFinishWorker; 252 private int mPasswordType = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 253 protected Stage mUiStage = Stage.Introduction; 254 private PasswordRequirementAdapter mPasswordRequirementAdapter; 255 private GlifLayout mLayout; 256 protected boolean mForFingerprint; 257 protected boolean mForFace; 258 protected boolean mForBiometrics; 259 260 private LockscreenCredential mFirstPassword; 261 private RecyclerView mPasswordRestrictionView; 262 protected boolean mIsAlphaMode; 263 protected FooterButton mSkipOrClearButton; 264 private FooterButton mNextButton; 265 private TextView mMessage; 266 protected CheckBox mAutoPinConfirmOption; 267 protected TextView mAutoConfirmSecurityMessage; 268 protected boolean mIsAutoPinConfirmOptionSetManually; 269 270 private TextChangedHandler mTextChangedHandler; 271 272 private static final int CONFIRM_EXISTING_REQUEST = 58; 273 static final int RESULT_FINISHED = RESULT_FIRST_USER; 274 /** Used to store the profile type for which pin/password is being set */ 275 protected enum ProfileType { 276 None, 277 Managed, 278 Private, 279 Other 280 }; 281 protected ProfileType mProfileType; 282 283 /** 284 * Keep track internally of where the user is in choosing a pattern. 285 */ 286 protected enum Stage { 287 288 Introduction( 289 R.string.lockpassword_choose_your_password_header, // password 290 SET_WORK_PROFILE_PASSWORD_HEADER, 291 R.string.lockpassword_choose_your_profile_password_header, 292 R.string.lockpassword_choose_your_password_header_for_fingerprint, 293 R.string.lockpassword_choose_your_password_header_for_face, 294 R.string.lockpassword_choose_your_password_header_for_biometrics, 295 R.string.private_space_choose_your_password_header, // private space password 296 R.string.lockpassword_choose_your_pin_header, // pin 297 SET_WORK_PROFILE_PIN_HEADER, 298 R.string.lockpassword_choose_your_profile_pin_header, 299 R.string.lockpassword_choose_your_pin_header_for_fingerprint, 300 R.string.lockpassword_choose_your_pin_header_for_face, 301 R.string.lockpassword_choose_your_pin_header_for_biometrics, 302 R.string.private_space_choose_your_pin_header, // private space pin 303 R.string.lock_settings_picker_biometrics_added_security_message, 304 R.string.lock_settings_picker_biometrics_added_security_message, 305 R.string.next_label), 306 307 NeedToConfirm( 308 R.string.lockpassword_confirm_your_password_header, 309 REENTER_WORK_PROFILE_PASSWORD_HEADER, 310 R.string.lockpassword_reenter_your_profile_password_header, 311 R.string.lockpassword_confirm_your_password_header, 312 R.string.lockpassword_confirm_your_password_header, 313 R.string.lockpassword_confirm_your_password_header, 314 R.string.lockpassword_confirm_your_password_header, 315 R.string.lockpassword_confirm_your_pin_header, 316 REENTER_WORK_PROFILE_PIN_HEADER, 317 R.string.lockpassword_reenter_your_profile_pin_header, 318 R.string.lockpassword_confirm_your_pin_header, 319 R.string.lockpassword_confirm_your_pin_header, 320 R.string.lockpassword_confirm_your_pin_header, 321 R.string.lockpassword_confirm_your_pin_header, 322 0, 323 0, 324 R.string.lockpassword_confirm_label), 325 326 ConfirmWrong( 327 R.string.lockpassword_confirm_passwords_dont_match, 328 UNDEFINED, 329 R.string.lockpassword_confirm_passwords_dont_match, 330 R.string.lockpassword_confirm_passwords_dont_match, 331 R.string.lockpassword_confirm_passwords_dont_match, 332 R.string.lockpassword_confirm_passwords_dont_match, 333 R.string.lockpassword_confirm_passwords_dont_match, 334 R.string.lockpassword_confirm_pins_dont_match, 335 UNDEFINED, 336 R.string.lockpassword_confirm_pins_dont_match, 337 R.string.lockpassword_confirm_pins_dont_match, 338 R.string.lockpassword_confirm_pins_dont_match, 339 R.string.lockpassword_confirm_pins_dont_match, 340 R.string.lockpassword_confirm_pins_dont_match, 341 0, 342 0, 343 R.string.lockpassword_confirm_label); 344 Stage(int hintInAlpha, String hintOverrideInAlphaForProfile, int hintInAlphaForProfile, int hintInAlphaForFingerprint, int hintInAlphaForFace, int hintInAlphaForBiometrics, int hintInAlphaForPrivateProfile, int hintInNumeric, String hintOverrideInNumericForProfile, int hintInNumericForProfile, int hintInNumericForFingerprint, int hintInNumericForFace, int hintInNumericForBiometrics, int hintInNumericForPrivateProfile, int messageInAlphaForBiometrics, int messageInNumericForBiometrics, int nextButtonText)345 Stage(int hintInAlpha, 346 String hintOverrideInAlphaForProfile, 347 int hintInAlphaForProfile, 348 int hintInAlphaForFingerprint, 349 int hintInAlphaForFace, 350 int hintInAlphaForBiometrics, 351 int hintInAlphaForPrivateProfile, 352 int hintInNumeric, 353 String hintOverrideInNumericForProfile, 354 int hintInNumericForProfile, 355 int hintInNumericForFingerprint, 356 int hintInNumericForFace, 357 int hintInNumericForBiometrics, 358 int hintInNumericForPrivateProfile, 359 int messageInAlphaForBiometrics, 360 int messageInNumericForBiometrics, 361 int nextButtonText) { 362 363 this.alphaHint = hintInAlpha; 364 this.alphaHintOverrideForProfile = hintOverrideInAlphaForProfile; 365 this.alphaHintForManagedProfile = hintInAlphaForProfile; 366 this.alphaHintForFingerprint = hintInAlphaForFingerprint; 367 this.alphaHintForFace = hintInAlphaForFace; 368 this.alphaHintForBiometrics = hintInAlphaForBiometrics; 369 this.alphaHintForPrivateProfile = hintInAlphaForPrivateProfile; 370 371 this.numericHint = hintInNumeric; 372 this.numericHintOverrideForProfile = hintOverrideInNumericForProfile; 373 this.numericHintForManagedProfile = hintInNumericForProfile; 374 this.numericHintForFingerprint = hintInNumericForFingerprint; 375 this.numericHintForFace = hintInNumericForFace; 376 this.numericHintForBiometrics = hintInNumericForBiometrics; 377 this.numericHintForPrivateProfile = hintInNumericForPrivateProfile; 378 379 this.alphaMessageForBiometrics = messageInAlphaForBiometrics; 380 this.numericMessageForBiometrics = messageInNumericForBiometrics; 381 382 this.buttonText = nextButtonText; 383 } 384 385 public static final int TYPE_NONE = 0; 386 public static final int TYPE_FINGERPRINT = 1; 387 public static final int TYPE_FACE = 2; 388 public static final int TYPE_BIOMETRIC = 3; 389 390 // Password header 391 public final int alphaHint; 392 public final int alphaHintForPrivateProfile; 393 public final String alphaHintOverrideForProfile; 394 public final int alphaHintForManagedProfile; 395 public final int alphaHintForFingerprint; 396 public final int alphaHintForFace; 397 public final int alphaHintForBiometrics; 398 399 // PIN header 400 public final int numericHint; 401 public final int numericHintForPrivateProfile; 402 public final String numericHintOverrideForProfile; 403 public final int numericHintForManagedProfile; 404 public final int numericHintForFingerprint; 405 public final int numericHintForFace; 406 public final int numericHintForBiometrics; 407 408 // Password description 409 public final int alphaMessageForBiometrics; 410 411 // PIN description 412 public final int numericMessageForBiometrics; 413 414 public final int buttonText; 415 getHint(Context context, boolean isAlpha, int type, ProfileType profile)416 public String getHint(Context context, boolean isAlpha, int type, ProfileType profile) { 417 if (isAlpha) { 418 if (android.os.Flags.allowPrivateProfile() 419 && android.multiuser.Flags.enablePrivateSpaceFeatures() 420 && profile.equals(ProfileType.Private)) { 421 return context.getString(alphaHintForPrivateProfile); 422 } else if (type == TYPE_FINGERPRINT) { 423 return context.getString(alphaHintForFingerprint); 424 } else if (type == TYPE_FACE) { 425 return context.getString(alphaHintForFace); 426 } else if (type == TYPE_BIOMETRIC) { 427 return context.getString(alphaHintForBiometrics); 428 } else if (profile.equals(ProfileType.Managed)) { 429 return context.getSystemService(DevicePolicyManager.class).getResources() 430 .getString(alphaHintOverrideForProfile, 431 () -> context.getString(alphaHintForManagedProfile)); 432 } else { 433 return context.getString(alphaHint); 434 } 435 } else { 436 if (android.os.Flags.allowPrivateProfile() 437 && android.multiuser.Flags.enablePrivateSpaceFeatures() 438 && profile.equals(ProfileType.Private)) { 439 return context.getString(numericHintForPrivateProfile); 440 } else if (type == TYPE_FINGERPRINT) { 441 return context.getString(numericHintForFingerprint); 442 } else if (type == TYPE_FACE) { 443 return context.getString(numericHintForFace); 444 } else if (type == TYPE_BIOMETRIC) { 445 return context.getString(numericHintForBiometrics); 446 } else if (profile.equals(ProfileType.Managed)) { 447 return context.getSystemService(DevicePolicyManager.class).getResources() 448 .getString(numericHintOverrideForProfile, 449 () -> context.getString(numericHintForManagedProfile)); 450 } else { 451 return context.getString(numericHint); 452 } 453 } 454 } 455 getMessage(boolean isAlpha, int type)456 public @StringRes int getMessage(boolean isAlpha, int type) { 457 switch (type) { 458 case TYPE_FINGERPRINT: 459 case TYPE_FACE: 460 case TYPE_BIOMETRIC: 461 return isAlpha ? alphaMessageForBiometrics : numericMessageForBiometrics; 462 463 case TYPE_NONE: 464 default: 465 return 0; 466 } 467 } 468 } 469 470 // required constructor for fragments ChooseLockPasswordFragment()471 public ChooseLockPasswordFragment() { 472 473 } 474 475 @Override onCreate(Bundle savedInstanceState)476 public void onCreate(Bundle savedInstanceState) { 477 super.onCreate(savedInstanceState); 478 mLockPatternUtils = new LockPatternUtils(getActivity()); 479 Intent intent = getActivity().getIntent(); 480 if (!(getActivity() instanceof ChooseLockPassword)) { 481 throw new SecurityException("Fragment contained in wrong activity"); 482 } 483 // Only take this argument into account if it belongs to the current profile. 484 mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras()); 485 mProfileType = getProfileType(); 486 mForFingerprint = intent.getBooleanExtra( 487 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); 488 mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false); 489 mForBiometrics = intent.getBooleanExtra( 490 ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false); 491 492 mPasswordType = intent.getIntExtra( 493 LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC); 494 mUnificationProfileId = intent.getIntExtra( 495 EXTRA_KEY_UNIFICATION_PROFILE_ID, UserHandle.USER_NULL); 496 497 mMinComplexity = intent.getIntExtra(EXTRA_KEY_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE); 498 mMinMetrics = intent.getParcelableExtra(EXTRA_KEY_MIN_METRICS); 499 if (mMinMetrics == null) mMinMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE); 500 501 mTextChangedHandler = new TextChangedHandler(); 502 } 503 504 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)505 public View onCreateView(LayoutInflater inflater, ViewGroup container, 506 Bundle savedInstanceState) { 507 return inflater.inflate(R.layout.choose_lock_password, container, false); 508 } 509 510 @Override onViewCreated(View view, Bundle savedInstanceState)511 public void onViewCreated(View view, Bundle savedInstanceState) { 512 super.onViewCreated(view, savedInstanceState); 513 514 mLayout = (GlifLayout) view; 515 516 // Make the password container consume the optical insets so the edit text is aligned 517 // with the sides of the parent visually. 518 ViewGroup container = view.findViewById(R.id.password_container); 519 container.setOpticalInsets(Insets.NONE); 520 521 final FooterBarMixin mixin = mLayout.getMixin(FooterBarMixin.class); 522 mixin.setSecondaryButton( 523 new FooterButton.Builder(getActivity()) 524 .setText(R.string.lockpassword_clear_label) 525 .setListener(this::onSkipOrClearButtonClick) 526 .setButtonType(FooterButton.ButtonType.SKIP) 527 .setTheme( 528 com.google.android.setupdesign.R.style.SudGlifButton_Secondary) 529 .build() 530 ); 531 mixin.setPrimaryButton( 532 new FooterButton.Builder(getActivity()) 533 .setText(R.string.next_label) 534 .setListener(this::onNextButtonClick) 535 .setButtonType(FooterButton.ButtonType.NEXT) 536 .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) 537 .build() 538 ); 539 mSkipOrClearButton = mixin.getSecondaryButton(); 540 mNextButton = mixin.getPrimaryButton(); 541 542 mMessage = view.findViewById(R.id.sud_layout_description); 543 mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_lock)); 544 545 mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mPasswordType 546 || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mPasswordType 547 || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mPasswordType; 548 549 final LinearLayout headerLayout = view.findViewById( 550 com.google.android.setupdesign.R.id.sud_layout_header); 551 setupPasswordRequirementsView(headerLayout); 552 553 mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity())); 554 mPasswordEntry = view.findViewById(R.id.password_entry); 555 mPasswordEntry.setOnEditorActionListener(this); 556 mPasswordEntry.addTextChangedListener(this); 557 mPasswordEntry.requestFocus(); 558 mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry); 559 560 // Fetch the AutoPinConfirmOption 561 mAutoPinConfirmOption = view.findViewById(R.id.auto_pin_confirm_enabler); 562 mAutoConfirmSecurityMessage = view.findViewById(R.id.auto_pin_confirm_security_message); 563 mIsAutoPinConfirmOptionSetManually = false; 564 setOnAutoConfirmOptionClickListener(); 565 if (mAutoPinConfirmOption != null) { 566 mAutoPinConfirmOption.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); 567 mAutoPinConfirmOption.setVisibility(View.GONE); 568 mAutoPinConfirmOption.setChecked(false); 569 } 570 571 final Activity activity = getActivity(); 572 573 int currentType = mPasswordEntry.getInputType(); 574 mPasswordEntry.setInputType(mIsAlphaMode ? currentType 575 : (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD)); 576 if (mIsAlphaMode) { 577 mPasswordEntry.setContentDescription( 578 getString(R.string.unlock_set_unlock_password_title)); 579 } else { 580 mPasswordEntry.setContentDescription( 581 getString(R.string.unlock_set_unlock_pin_title)); 582 } 583 // Can't set via XML since setInputType resets the fontFamily to null 584 mPasswordEntry.setTypeface(Typeface.create( 585 getContext().getString(com.android.internal.R.string.config_headlineFontFamily), 586 Typeface.NORMAL)); 587 588 Intent intent = getActivity().getIntent(); 589 final boolean confirmCredentials = intent.getBooleanExtra( 590 ChooseLockGeneric.CONFIRM_CREDENTIALS, true); 591 mCurrentCredential = intent.getParcelableExtra( 592 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 593 mRequestGatekeeperPassword = intent.getBooleanExtra( 594 ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, false); 595 mRequestWriteRepairModePassword = intent.getBooleanExtra( 596 ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW, false); 597 if (savedInstanceState == null) { 598 updateStage(Stage.Introduction); 599 if (confirmCredentials) { 600 final ChooseLockSettingsHelper.Builder builder = 601 new ChooseLockSettingsHelper.Builder(getActivity()); 602 builder.setRequestCode(CONFIRM_EXISTING_REQUEST) 603 .setTitle(getString(R.string.unlock_set_unlock_launch_picker_title)) 604 .setReturnCredentials(true) 605 .setRequestGatekeeperPasswordHandle(mRequestGatekeeperPassword) 606 .setRequestWriteRepairModePassword(mRequestWriteRepairModePassword) 607 .setUserId(mUserId) 608 .show(); 609 } 610 } else { 611 612 // restore from previous state 613 mFirstPassword = savedInstanceState.getParcelable(KEY_FIRST_PASSWORD); 614 final String state = savedInstanceState.getString(KEY_UI_STAGE); 615 if (state != null) { 616 mUiStage = Stage.valueOf(state); 617 updateStage(mUiStage); 618 } 619 mIsAutoPinConfirmOptionSetManually = 620 savedInstanceState.getBoolean(KEY_IS_AUTO_CONFIRM_CHECK_MANUALLY_CHANGED); 621 622 mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_CREDENTIAL); 623 624 // Re-attach to the exiting worker if there is one. 625 mSaveAndFinishWorker = (SaveAndFinishWorker) getFragmentManager().findFragmentByTag( 626 FRAGMENT_TAG_SAVE_AND_FINISH); 627 } 628 629 if (activity instanceof SettingsActivity) { 630 final SettingsActivity sa = (SettingsActivity) activity; 631 String title = Stage.Introduction.getHint( 632 getContext(), mIsAlphaMode, getStageType(), mProfileType); 633 sa.setTitle(title); 634 mLayout.setHeaderText(title); 635 } 636 } 637 638 @Override onDestroy()639 public void onDestroy() { 640 super.onDestroy(); 641 if (mCurrentCredential != null) { 642 mCurrentCredential.zeroize(); 643 } 644 // Force a garbage collection immediately to remove remnant of user password shards 645 // from memory. 646 System.gc(); 647 System.runFinalization(); 648 System.gc(); 649 } 650 getStageType()651 protected int getStageType() { 652 if (mForFingerprint) { 653 return Stage.TYPE_FINGERPRINT; 654 } else if (mForFace) { 655 return Stage.TYPE_FACE; 656 } else if (mForBiometrics) { 657 return Stage.TYPE_BIOMETRIC; 658 } else { 659 return Stage.TYPE_NONE; 660 } 661 } 662 setupPasswordRequirementsView(@ullable ViewGroup view)663 private void setupPasswordRequirementsView(@Nullable ViewGroup view) { 664 if (view == null) { 665 return; 666 } 667 668 createHintMessageView(view); 669 mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity())); 670 mPasswordRequirementAdapter = new PasswordRequirementAdapter(getActivity()); 671 mPasswordRestrictionView.setAdapter(mPasswordRequirementAdapter); 672 view.addView(mPasswordRestrictionView); 673 } 674 createHintMessageView(ViewGroup view)675 private void createHintMessageView(ViewGroup view) { 676 if (mPasswordRestrictionView != null) { 677 return; 678 } 679 680 final TextView sucTitleView = view.findViewById(R.id.suc_layout_title); 681 final ViewGroup.MarginLayoutParams titleLayoutParams = 682 (ViewGroup.MarginLayoutParams) sucTitleView.getLayoutParams(); 683 mPasswordRestrictionView = new RecyclerView(getActivity()); 684 final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 685 LinearLayout.LayoutParams.MATCH_PARENT, 686 LinearLayout.LayoutParams.WRAP_CONTENT); 687 lp.setMargins(titleLayoutParams.leftMargin, getResources().getDimensionPixelSize( 688 R.dimen.password_requirement_view_margin_top), titleLayoutParams.leftMargin, 0); 689 mPasswordRestrictionView.setLayoutParams(lp); 690 } 691 692 @Override getMetricsCategory()693 public int getMetricsCategory() { 694 return SettingsEnums.CHOOSE_LOCK_PASSWORD; 695 } 696 697 @Override onResume()698 public void onResume() { 699 super.onResume(); 700 updateStage(mUiStage); 701 if (mSaveAndFinishWorker != null) { 702 mSaveAndFinishWorker.setListener(this); 703 } else { 704 mPasswordEntry.requestFocus(); 705 mPasswordEntry.scheduleShowSoftInput(); 706 } 707 } 708 709 @Override onPause()710 public void onPause() { 711 if (mSaveAndFinishWorker != null) { 712 mSaveAndFinishWorker.setListener(null); 713 } 714 super.onPause(); 715 } 716 717 @Override onSaveInstanceState(Bundle outState)718 public void onSaveInstanceState(Bundle outState) { 719 super.onSaveInstanceState(outState); 720 outState.putString(KEY_UI_STAGE, mUiStage.name()); 721 outState.putParcelable(KEY_FIRST_PASSWORD, mFirstPassword); 722 if (mCurrentCredential != null) { 723 outState.putParcelable(KEY_CURRENT_CREDENTIAL, mCurrentCredential.duplicate()); 724 } 725 outState.putBoolean(KEY_IS_AUTO_CONFIRM_CHECK_MANUALLY_CHANGED, 726 mIsAutoPinConfirmOptionSetManually); 727 } 728 729 @Override onActivityResult(int requestCode, int resultCode, Intent data)730 public void onActivityResult(int requestCode, int resultCode, 731 Intent data) { 732 super.onActivityResult(requestCode, resultCode, data); 733 switch (requestCode) { 734 case CONFIRM_EXISTING_REQUEST: 735 if (resultCode != Activity.RESULT_OK) { 736 getActivity().setResult(RESULT_FINISHED); 737 getActivity().finish(); 738 } else { 739 mCurrentCredential = data.getParcelableExtra( 740 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 741 } 742 break; 743 } 744 } 745 getRedactionInterstitialIntent(Context context)746 protected Intent getRedactionInterstitialIntent(Context context) { 747 return RedactionInterstitial.createStartIntent(context, mUserId); 748 } 749 updateStage(Stage stage)750 protected void updateStage(Stage stage) { 751 final Stage previousStage = mUiStage; 752 mUiStage = stage; 753 updateUi(); 754 755 // If the stage changed, announce the header for accessibility. This 756 // is a no-op when accessibility is disabled. 757 if (previousStage != stage) { 758 mLayout.announceForAccessibility(mLayout.getHeaderText()); 759 } 760 } 761 762 /** 763 * Validates PIN/Password and returns the validation result and updates mValidationErrors 764 * to reflect validation results. 765 * 766 * @param credential credential the user typed in. 767 * @return whether password satisfies all the requirements. 768 */ 769 @VisibleForTesting validatePassword(LockscreenCredential credential)770 boolean validatePassword(LockscreenCredential credential) { 771 mValidationErrors = PasswordMetrics.validateCredential(mMinMetrics, mMinComplexity, 772 credential); 773 if (mValidationErrors.isEmpty() && mLockPatternUtils.checkPasswordHistory( 774 credential.getCredential(), getPasswordHistoryHashFactor(), mUserId)) { 775 mValidationErrors = 776 Collections.singletonList(new PasswordValidationError(RECENTLY_USED)); 777 } 778 return mValidationErrors.isEmpty(); 779 } 780 781 /** 782 * Lazily compute and return the history hash factor of the current user (mUserId), used for 783 * password history check. 784 */ getPasswordHistoryHashFactor()785 private byte[] getPasswordHistoryHashFactor() { 786 if (mPasswordHistoryHashFactor == null) { 787 mPasswordHistoryHashFactor = mLockPatternUtils.getPasswordHistoryHashFactor( 788 mCurrentCredential != null ? mCurrentCredential 789 : LockscreenCredential.createNone(), mUserId); 790 } 791 return mPasswordHistoryHashFactor; 792 } 793 handleNext()794 public void handleNext() { 795 if (mSaveAndFinishWorker != null) return; 796 // TODO(b/120484642): This is a point of entry for passwords from the UI 797 final Editable passwordText = mPasswordEntry.getText(); 798 if (TextUtils.isEmpty(passwordText)) { 799 return; 800 } 801 mChosenPassword = mIsAlphaMode ? LockscreenCredential.createPassword(passwordText) 802 : LockscreenCredential.createPin(passwordText); 803 if (mUiStage == Stage.Introduction) { 804 if (validatePassword(mChosenPassword)) { 805 mFirstPassword = mChosenPassword; 806 mPasswordEntry.setText(""); 807 updateStage(Stage.NeedToConfirm); 808 } else { 809 mChosenPassword.zeroize(); 810 } 811 } else if (mUiStage == Stage.NeedToConfirm) { 812 if (mChosenPassword.equals(mFirstPassword)) { 813 startSaveAndFinish(); 814 } else { 815 CharSequence tmp = mPasswordEntry.getText(); 816 if (tmp != null) { 817 Selection.setSelection((Spannable) tmp, 0, tmp.length()); 818 } 819 updateStage(Stage.ConfirmWrong); 820 mChosenPassword.zeroize(); 821 } 822 } 823 } 824 setNextEnabled(boolean enabled)825 protected void setNextEnabled(boolean enabled) { 826 mNextButton.setEnabled(enabled); 827 } 828 setNextText(int text)829 protected void setNextText(int text) { 830 mNextButton.setText(getActivity(), text); 831 } 832 onSkipOrClearButtonClick(View view)833 protected void onSkipOrClearButtonClick(View view) { 834 mPasswordEntry.setText(""); 835 } 836 onNextButtonClick(View view)837 protected void onNextButtonClick(View view) { 838 handleNext(); 839 } 840 onEditorAction(TextView v, int actionId, KeyEvent event)841 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 842 // Check if this was the result of hitting the enter or "done" key 843 if (actionId == EditorInfo.IME_NULL 844 || actionId == EditorInfo.IME_ACTION_DONE 845 || actionId == EditorInfo.IME_ACTION_NEXT) { 846 handleNext(); 847 return true; 848 } 849 return false; 850 } 851 852 /** 853 * @param errorCode error code returned from password validation. 854 * @return an array of messages describing the error, important messages come first. 855 */ convertErrorCodeToMessages()856 String[] convertErrorCodeToMessages() { 857 List<String> messages = new ArrayList<>(); 858 for (PasswordValidationError error : mValidationErrors) { 859 switch (error.errorCode) { 860 case CONTAINS_INVALID_CHARACTERS: 861 messages.add(getString(R.string.lockpassword_illegal_character)); 862 break; 863 case NOT_ENOUGH_UPPER_CASE: 864 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 865 R.string.lockpassword_password_requires_uppercase)); 866 break; 867 case NOT_ENOUGH_LOWER_CASE: 868 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 869 R.string.lockpassword_password_requires_lowercase)); 870 break; 871 case NOT_ENOUGH_LETTERS: 872 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 873 R.string.lockpassword_password_requires_letters)); 874 break; 875 case NOT_ENOUGH_DIGITS: 876 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 877 R.string.lockpassword_password_requires_numeric)); 878 break; 879 case NOT_ENOUGH_SYMBOLS: 880 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 881 R.string.lockpassword_password_requires_symbols)); 882 break; 883 case NOT_ENOUGH_NON_LETTER: 884 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 885 R.string.lockpassword_password_requires_nonletter)); 886 break; 887 case NOT_ENOUGH_NON_DIGITS: 888 messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement, 889 R.string.lockpassword_password_requires_nonnumerical)); 890 break; 891 case TOO_SHORT: 892 String message = StringUtil.getIcuPluralsString(getContext(), 893 error.requirement, 894 mIsAlphaMode 895 ? R.string.lockpassword_password_too_short 896 : R.string.lockpassword_pin_too_short); 897 if (LockPatternUtils.isAutoPinConfirmFeatureAvailable() 898 && !mIsAlphaMode 899 && error.requirement < MIN_AUTO_PIN_REQUIREMENT_LENGTH) { 900 Map<String, Object> arguments = new HashMap<>(); 901 arguments.put("count", error.requirement); 902 arguments.put("minAutoConfirmLen", MIN_AUTO_PIN_REQUIREMENT_LENGTH); 903 message = StringUtil.getIcuPluralsString(getContext(), 904 arguments, 905 R.string.lockpassword_pin_too_short_autoConfirm_extra_message); 906 } 907 messages.add(message); 908 break; 909 case TOO_SHORT_WHEN_ALL_NUMERIC: 910 messages.add( 911 StringUtil.getIcuPluralsString(getContext(), error.requirement, 912 R.string.lockpassword_password_too_short_all_numeric)); 913 break; 914 case TOO_LONG: 915 messages.add(StringUtil.getIcuPluralsString(getContext(), 916 error.requirement + 1, mIsAlphaMode 917 ? R.string.lockpassword_password_too_long 918 : R.string.lockpassword_pin_too_long)); 919 break; 920 case CONTAINS_SEQUENCE: 921 messages.add(getString(R.string.lockpassword_pin_no_sequential_digits)); 922 break; 923 case RECENTLY_USED: 924 DevicePolicyManager devicePolicyManager = 925 getContext().getSystemService(DevicePolicyManager.class); 926 if (mIsAlphaMode) { 927 messages.add(devicePolicyManager.getResources().getString( 928 PASSWORD_RECENTLY_USED, 929 () -> getString(R.string.lockpassword_password_recently_used))); 930 } else { 931 messages.add(devicePolicyManager.getResources().getString( 932 PIN_RECENTLY_USED, 933 () -> getString(R.string.lockpassword_pin_recently_used))); 934 } 935 break; 936 default: 937 Log.wtf(TAG, "unknown error validating password: " + error); 938 } 939 } 940 941 return messages.toArray(new String[0]); 942 } 943 944 /** 945 * Update the hint based on current Stage and length of password entry 946 */ updateUi()947 protected void updateUi() { 948 final boolean canInput = mSaveAndFinishWorker == null; 949 950 LockscreenCredential password = mIsAlphaMode 951 ? LockscreenCredential.createPassword(mPasswordEntry.getText()) 952 : LockscreenCredential.createPin(mPasswordEntry.getText()); 953 final int length = password.size(); 954 if (mUiStage == Stage.Introduction) { 955 mPasswordRestrictionView.setVisibility(View.VISIBLE); 956 final boolean passwordCompliant = validatePassword(password); 957 String[] messages = convertErrorCodeToMessages(); 958 // Update the fulfillment of requirements. 959 mPasswordRequirementAdapter.setRequirements(messages); 960 // set the visibility of pin_auto_confirm option accordingly 961 setAutoPinConfirmOption(passwordCompliant, length); 962 // Enable/Disable the next button accordingly. 963 setNextEnabled(passwordCompliant); 964 } else { 965 // Hide password requirement view when we are just asking user to confirm the pw. 966 mPasswordRestrictionView.setVisibility(View.GONE); 967 setHeaderText(mUiStage.getHint(getContext(), mIsAlphaMode, getStageType(), 968 mProfileType)); 969 setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE); 970 mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0)); 971 972 // Hide the pin_confirm option when we are just asking user to confirm the pwd. 973 mAutoPinConfirmOption.setVisibility(View.GONE); 974 mAutoConfirmSecurityMessage.setVisibility(View.GONE); 975 } 976 final int stage = getStageType(); 977 if (getStageType() != Stage.TYPE_NONE) { 978 int message = mUiStage.getMessage(mIsAlphaMode, stage); 979 if (message != 0) { 980 mMessage.setVisibility(View.VISIBLE); 981 mMessage.setText(message); 982 } else { 983 mMessage.setVisibility(View.INVISIBLE); 984 } 985 } else { 986 mMessage.setVisibility(View.GONE); 987 } 988 989 setNextText(mUiStage.buttonText); 990 mPasswordEntryInputDisabler.setInputEnabled(canInput); 991 password.zeroize(); 992 } 993 toVisibility(boolean visibleOrGone)994 protected int toVisibility(boolean visibleOrGone) { 995 return visibleOrGone ? View.VISIBLE : View.GONE; 996 } 997 setAutoPinConfirmOption(boolean enabled, int length)998 private void setAutoPinConfirmOption(boolean enabled, int length) { 999 if (!LockPatternUtils.isAutoPinConfirmFeatureAvailable() 1000 || mAutoPinConfirmOption == null) { 1001 return; 1002 } 1003 if (enabled && !mIsAlphaMode && isAutoPinConfirmPossible(length)) { 1004 mAutoPinConfirmOption.setVisibility(View.VISIBLE); 1005 mAutoConfirmSecurityMessage.setVisibility(View.VISIBLE); 1006 if (!mIsAutoPinConfirmOptionSetManually) { 1007 mAutoPinConfirmOption.setChecked(length == MIN_AUTO_PIN_REQUIREMENT_LENGTH); 1008 } 1009 } else { 1010 mAutoPinConfirmOption.setVisibility(View.GONE); 1011 mAutoConfirmSecurityMessage.setVisibility(View.GONE); 1012 mAutoPinConfirmOption.setChecked(false); 1013 } 1014 } 1015 isAutoPinConfirmPossible(int currentPinLength)1016 private boolean isAutoPinConfirmPossible(int currentPinLength) { 1017 return currentPinLength >= MIN_AUTO_PIN_REQUIREMENT_LENGTH; 1018 } 1019 setOnAutoConfirmOptionClickListener()1020 private void setOnAutoConfirmOptionClickListener() { 1021 if (mAutoPinConfirmOption != null) { 1022 mAutoPinConfirmOption.setOnClickListener((v) -> { 1023 mIsAutoPinConfirmOptionSetManually = true; 1024 }); 1025 } 1026 } 1027 setHeaderText(String text)1028 private void setHeaderText(String text) { 1029 // Only set the text if it is different than the existing one to avoid announcing again. 1030 if (!TextUtils.isEmpty(mLayout.getHeaderText()) 1031 && mLayout.getHeaderText().toString().equals(text)) { 1032 return; 1033 } 1034 mLayout.setHeaderText(text); 1035 } 1036 afterTextChanged(Editable s)1037 public void afterTextChanged(Editable s) { 1038 // Changing the text while error displayed resets to NeedToConfirm state 1039 if (mUiStage == Stage.ConfirmWrong) { 1040 mUiStage = Stage.NeedToConfirm; 1041 } 1042 // Schedule the UI update. 1043 mTextChangedHandler.notifyAfterTextChanged(); 1044 } 1045 beforeTextChanged(CharSequence s, int start, int count, int after)1046 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 1047 1048 } 1049 onTextChanged(CharSequence s, int start, int before, int count)1050 public void onTextChanged(CharSequence s, int start, int before, int count) { 1051 1052 } 1053 startSaveAndFinish()1054 private void startSaveAndFinish() { 1055 if (mSaveAndFinishWorker != null) { 1056 Log.w(TAG, "startSaveAndFinish with an existing SaveAndFinishWorker."); 1057 return; 1058 } 1059 1060 ConfirmDeviceCredentialUtils.hideImeImmediately( 1061 getActivity().getWindow().getDecorView()); 1062 1063 mPasswordEntryInputDisabler.setInputEnabled(false); 1064 mSaveAndFinishWorker = new SaveAndFinishWorker(); 1065 mSaveAndFinishWorker 1066 .setListener(this) 1067 .setRequestGatekeeperPasswordHandle(mRequestGatekeeperPassword) 1068 .setRequestWriteRepairModePassword(mRequestWriteRepairModePassword); 1069 1070 getFragmentManager().beginTransaction().add(mSaveAndFinishWorker, 1071 FRAGMENT_TAG_SAVE_AND_FINISH).commit(); 1072 getFragmentManager().executePendingTransactions(); 1073 1074 final Intent intent = getActivity().getIntent(); 1075 if (mUnificationProfileId != UserHandle.USER_NULL) { 1076 try (LockscreenCredential profileCredential = (LockscreenCredential) 1077 intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) { 1078 mSaveAndFinishWorker.setProfileToUnify(mUnificationProfileId, 1079 profileCredential); 1080 } 1081 } 1082 // update the setting before triggering the password save workflow, 1083 // so that pinLength information is stored accordingly when setting is turned on. 1084 mLockPatternUtils.setAutoPinConfirm( 1085 (mAutoPinConfirmOption != null && mAutoPinConfirmOption.isChecked()), 1086 mUserId); 1087 1088 mSaveAndFinishWorker.start(mLockPatternUtils, 1089 mChosenPassword, mCurrentCredential, mUserId); 1090 } 1091 1092 @Override onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData)1093 public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) { 1094 getActivity().setResult(RESULT_FINISHED, resultData); 1095 1096 if (mChosenPassword != null) { 1097 mChosenPassword.zeroize(); 1098 } 1099 if (mCurrentCredential != null) { 1100 mCurrentCredential.zeroize(); 1101 } 1102 if (mFirstPassword != null) { 1103 mFirstPassword.zeroize(); 1104 } 1105 1106 mPasswordEntry.setText(""); 1107 1108 if (!wasSecureBefore) { 1109 Intent intent = getRedactionInterstitialIntent(getActivity()); 1110 if (intent != null) { 1111 startActivity(intent); 1112 } 1113 } 1114 1115 if (mLayout != null) { 1116 mLayout.announceForAccessibility( 1117 getString(R.string.accessibility_setup_password_complete)); 1118 } 1119 1120 getActivity().finish(); 1121 } 1122 1123 class TextChangedHandler extends Handler { 1124 private static final int ON_TEXT_CHANGED = 1; 1125 private static final int DELAY_IN_MILLISECOND = 100; 1126 1127 /** 1128 * With the introduction of delay, we batch processing the text changed event to reduce 1129 * unnecessary UI updates. 1130 */ notifyAfterTextChanged()1131 private void notifyAfterTextChanged() { 1132 removeMessages(ON_TEXT_CHANGED); 1133 sendEmptyMessageDelayed(ON_TEXT_CHANGED, DELAY_IN_MILLISECOND); 1134 } 1135 1136 @Override handleMessage(Message msg)1137 public void handleMessage(Message msg) { 1138 if (getActivity() == null) { 1139 return; 1140 } 1141 if (msg.what == ON_TEXT_CHANGED) { 1142 updateUi(); 1143 } 1144 } 1145 } 1146 getProfileType()1147 private ProfileType getProfileType() { 1148 UserManager userManager = getContext().createContextAsUser(UserHandle.of(mUserId), 1149 /*flags=*/0).getSystemService(UserManager.class); 1150 if (userManager.isManagedProfile()) { 1151 return ProfileType.Managed; 1152 } else if (android.os.Flags.allowPrivateProfile() 1153 && android.multiuser.Flags.enablePrivateSpaceFeatures() 1154 && userManager.isPrivateProfile()) { 1155 return ProfileType.Private; 1156 } else if (userManager.isProfile()) { 1157 return ProfileType.Other; 1158 } 1159 return ProfileType.None; 1160 } 1161 } 1162 } 1163