blob: ff94d8b89562510b6d9c7ecb279770817c43a22b [file] [log] [blame]
Jim Miller00d24762009-12-22 19:04:57 -08001/*
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
Maurice Lam2eb170c2017-04-28 16:18:47 -070017package com.android.settings.password;
Jim Miller00d24762009-12-22 19:04:57 -080018
Bernard Chau92db5bf2018-12-17 18:03:24 +000019import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
Maurice Lamc41e4082017-04-27 19:04:46 -070020import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
Maurice Lamc41e4082017-04-27 19:04:46 -070021
Pavel Grafov69cac2c2019-08-07 13:21:53 +010022import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
23import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
24import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS;
25import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LETTERS;
26import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LOWER_CASE;
27import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_DIGITS;
28import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_LETTER;
29import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_SYMBOLS;
30import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
31import static com.android.internal.widget.PasswordValidationError.RECENTLY_USED;
32import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
33import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
Bernard Chau92db5bf2018-12-17 18:03:24 +000034import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
35
Jim Miller00d24762009-12-22 19:04:57 -080036import android.app.Activity;
Jim Milleraf366a32010-03-25 18:45:22 -070037import android.app.admin.DevicePolicyManager;
Bernard Chau92db5bf2018-12-17 18:03:24 +000038import android.app.admin.DevicePolicyManager.PasswordComplexity;
Andrew Scull27ca2632016-08-02 14:18:58 +010039import android.app.admin.PasswordMetrics;
Fan Zhang31b21002019-01-16 13:49:47 -080040import android.app.settings.SettingsEnums;
Jim Miller0698a212014-10-16 19:49:07 -070041import android.content.Context;
Jim Miller00d24762009-12-22 19:04:57 -080042import android.content.Intent;
Maurice Lam9990f392017-06-28 15:06:09 -070043import android.content.res.Resources.Theme;
Maurice Lamedb39442017-04-27 18:54:33 -070044import android.graphics.Insets;
Andrew Sappersteinccbb4cf2017-07-06 14:30:28 -070045import android.graphics.Typeface;
Jim Miller00d24762009-12-22 19:04:57 -080046import android.os.Bundle;
Tony Mak9ba765b2016-08-02 17:09:53 +010047import android.os.Handler;
48import android.os.Message;
Jim Miller00d24762009-12-22 19:04:57 -080049import android.text.Editable;
Jim Miller2e28ace2010-12-15 10:07:16 -080050import android.text.InputType;
Jim Miller122b6c82010-02-10 19:53:58 -080051import android.text.Selection;
52import android.text.Spannable;
Jim Miller00d24762009-12-22 19:04:57 -080053import android.text.TextUtils;
Jim Miller122b6c82010-02-10 19:53:58 -080054import android.text.TextWatcher;
Andres Morales91e6c492015-05-15 15:20:33 -070055import android.util.Log;
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +000056import android.util.Pair;
Jim Miller122b6c82010-02-10 19:53:58 -080057import android.view.KeyEvent;
Jim Miller17e9e192010-12-07 20:41:41 -080058import android.view.LayoutInflater;
Jim Miller00d24762009-12-22 19:04:57 -080059import android.view.View;
Jason Monk39b46742015-09-10 15:52:51 -040060import android.view.ViewGroup;
Maurice Lamc41e4082017-04-27 19:04:46 -070061import android.view.inputmethod.EditorInfo;
Jim Miller00d24762009-12-22 19:04:57 -080062import android.widget.TextView;
Jim Miller122b6c82010-02-10 19:53:58 -080063import android.widget.TextView.OnEditorActionListener;
Jim Miller00d24762009-12-22 19:04:57 -080064
Fan Zhang23f8d592018-08-28 15:11:40 -070065import androidx.annotation.StringRes;
66import androidx.fragment.app.Fragment;
67import androidx.recyclerview.widget.LinearLayoutManager;
68import androidx.recyclerview.widget.RecyclerView;
69
Bernard Chau92db5bf2018-12-17 18:03:24 +000070import com.android.internal.annotations.VisibleForTesting;
Jason Monk39b46742015-09-10 15:52:51 -040071import com.android.internal.widget.LockPatternUtils;
72import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
Rubin Xu010116a2019-09-11 17:36:37 +010073import com.android.internal.widget.LockscreenCredential;
Pavel Grafov69cac2c2019-08-07 13:21:53 +010074import com.android.internal.widget.PasswordValidationError;
Jason Monk39b46742015-09-10 15:52:51 -040075import com.android.internal.widget.TextViewInputDisabler;
Maurice Lam2eb170c2017-04-28 16:18:47 -070076import com.android.settings.EncryptionInterstitial;
77import com.android.settings.R;
78import com.android.settings.SettingsActivity;
Maurice Lam9990f392017-06-28 15:06:09 -070079import com.android.settings.SetupWizardUtils;
Maurice Lam2eb170c2017-04-28 16:18:47 -070080import com.android.settings.Utils;
Doris Ling72489722017-11-16 11:03:40 -080081import com.android.settings.core.InstrumentedFragment;
Jason Monk39b46742015-09-10 15:52:51 -040082import com.android.settings.notification.RedactionInterstitial;
Tarandeep Singhb0bcbed2017-07-14 13:22:07 -070083import com.android.settings.widget.ImeAwareEditText;
Pasty Changc1f86002018-12-11 02:22:55 +000084
pastychang9bdb59a2019-01-21 09:49:15 +080085import com.google.android.setupcompat.template.FooterBarMixin;
86import com.google.android.setupcompat.template.FooterButton;
Pasty Changc1f86002018-12-11 02:22:55 +000087import com.google.android.setupdesign.GlifLayout;
Jason Monk39b46742015-09-10 15:52:51 -040088
Tony Mak0bbcdcc2016-07-12 11:19:45 +010089import java.util.ArrayList;
Pavel Grafov69cac2c2019-08-07 13:21:53 +010090import java.util.Collections;
Tony Mak0bbcdcc2016-07-12 11:19:45 +010091import java.util.List;
92
Fabrice Di Meglio263bcc82014-01-17 19:17:58 -080093public class ChooseLockPassword extends SettingsActivity {
Andres Morales91e6c492015-05-15 15:20:33 -070094 private static final String TAG = "ChooseLockPassword";
95
Jim Miller17e9e192010-12-07 20:41:41 -080096 @Override
97 public Intent getIntent() {
98 Intent modIntent = new Intent(super.getIntent());
Maurice Lam6b19fa92014-11-25 19:25:56 -080099 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
Jim Miller17e9e192010-12-07 20:41:41 -0800100 return modIntent;
101 }
Jim Miller00d24762009-12-22 19:04:57 -0800102
Maurice Lam9990f392017-06-28 15:06:09 -0700103 @Override
104 protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
105 resid = SetupWizardUtils.getTheme(getIntent());
106 super.onApplyThemeResource(theme, resid, first);
107 }
108
Maurice Lam2eb170c2017-04-28 16:18:47 -0700109 public static class IntentBuilder {
Jim Miller0698a212014-10-16 19:49:07 -0700110
Maurice Lam2eb170c2017-04-28 16:18:47 -0700111 private final Intent mIntent;
Clara Bayarrife432e82015-10-12 12:07:02 +0100112
Maurice Lam2eb170c2017-04-28 16:18:47 -0700113 public IntentBuilder(Context context) {
114 mIntent = new Intent(context, ChooseLockPassword.class);
115 mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
116 mIntent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false);
Pavel Grafov40e187b2017-10-11 22:57:09 +0100117 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
Maurice Lam2eb170c2017-04-28 16:18:47 -0700118 }
Andres Moralesa0e12362015-04-02 09:00:41 -0700119
Maurice Lam2eb170c2017-04-28 16:18:47 -0700120 public IntentBuilder setPasswordQuality(int quality) {
121 mIntent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
122 return this;
123 }
Clara Bayarrife432e82015-10-12 12:07:02 +0100124
Maurice Lam2eb170c2017-04-28 16:18:47 -0700125 public IntentBuilder setUserId(int userId) {
126 mIntent.putExtra(Intent.EXTRA_USER_ID, userId);
127 return this;
128 }
129
130 public IntentBuilder setChallenge(long challenge) {
131 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
132 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
133 return this;
134 }
135
Rubin Xu010116a2019-09-11 17:36:37 +0100136 public IntentBuilder setPassword(LockscreenCredential password) {
Maurice Lam2eb170c2017-04-28 16:18:47 -0700137 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, password);
138 return this;
139 }
140
Maurice Lamb49526e2017-05-31 17:55:43 -0700141 public IntentBuilder setForFingerprint(boolean forFingerprint) {
142 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
143 return this;
144 }
145
Kevin Chyn81dc0292018-06-28 14:59:38 -0700146 public IntentBuilder setForFace(boolean forFace) {
147 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace);
148 return this;
149 }
150
Bernard Chau92db5bf2018-12-17 18:03:24 +0000151 public IntentBuilder setRequestedMinComplexity(@PasswordComplexity int level) {
152 mIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, level);
153 return this;
154 }
155
Maurice Lam2eb170c2017-04-28 16:18:47 -0700156 public Intent build() {
157 return mIntent;
158 }
Clara Bayarrife432e82015-10-12 12:07:02 +0100159 }
160
Jim Miller17e9e192010-12-07 20:41:41 -0800161 @Override
Amith Yamasania677ee22013-07-26 13:38:41 -0700162 protected boolean isValidFragment(String fragmentName) {
163 if (ChooseLockPasswordFragment.class.getName().equals(fragmentName)) return true;
164 return false;
165 }
166
Maurice Lam6b19fa92014-11-25 19:25:56 -0800167 /* package */ Class<? extends Fragment> getFragmentClass() {
168 return ChooseLockPasswordFragment.class;
169 }
170
Amith Yamasania677ee22013-07-26 13:38:41 -0700171 @Override
Udam Saini71fde522016-03-30 13:38:05 -0700172 protected void onCreate(Bundle savedInstanceState) {
Jim Miller17e9e192010-12-07 20:41:41 -0800173 super.onCreate(savedInstanceState);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700174 final boolean forFingerprint = getIntent()
Maurice Lamb49526e2017-05-31 17:55:43 -0700175 .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700176 final boolean forFace = getIntent()
177 .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
178
179 CharSequence msg = getText(R.string.lockpassword_choose_your_screen_lock_header);
180 if (forFingerprint) {
181 msg = getText(R.string.lockpassword_choose_your_password_header_for_fingerprint);
182 } else if (forFace) {
183 msg = getText(R.string.lockpassword_choose_your_password_header_for_face);
184 }
185
Fabrice Di Meglio263bcc82014-01-17 19:17:58 -0800186 setTitle(msg);
Fan Zhang9db66a52019-05-10 14:18:33 -0700187 findViewById(R.id.content_parent).setFitsSystemWindows(false);
Jim Miller17e9e192010-12-07 20:41:41 -0800188 }
Jim Miller122b6c82010-02-10 19:53:58 -0800189
Doris Ling72489722017-11-16 11:03:40 -0800190 public static class ChooseLockPasswordFragment extends InstrumentedFragment
pastychang76ad11c2019-01-18 14:28:27 +0800191 implements OnEditorActionListener, TextWatcher, SaveAndFinishWorker.Listener {
Rubin Xu010116a2019-09-11 17:36:37 +0100192 private static final String KEY_FIRST_PASSWORD = "first_password";
Jim Miller17e9e192010-12-07 20:41:41 -0800193 private static final String KEY_UI_STAGE = "ui_stage";
Rubin Xu010116a2019-09-11 17:36:37 +0100194 private static final String KEY_CURRENT_CREDENTIAL = "current_credential";
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700195 private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
Andres Moralesa0e12362015-04-02 09:00:41 -0700196
Rubin Xu010116a2019-09-11 17:36:37 +0100197 private LockscreenCredential mCurrentCredential;
198 private LockscreenCredential mChosenPassword;
Andres Morales6609b0c2015-04-12 15:38:25 -0700199 private boolean mHasChallenge;
200 private long mChallenge;
Tarandeep Singhb0bcbed2017-07-14 13:22:07 -0700201 private ImeAwareEditText mPasswordEntry;
Xiyuan Xiaf2c2c192015-05-15 13:37:04 -0700202 private TextViewInputDisabler mPasswordEntryInputDisabler;
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100203
204 // Minimum password metrics enforced by admins.
205 private PasswordMetrics mMinMetrics;
206 private List<PasswordValidationError> mValidationErrors;
207
208 @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE;
Maurice Lamedb39442017-04-27 18:54:33 -0700209 protected int mUserId;
Rubin Xuc33e2a12018-03-30 20:51:24 +0100210 private byte[] mPasswordHistoryHashFactor;
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100211
Jim Miller17e9e192010-12-07 20:41:41 -0800212 private LockPatternUtils mLockPatternUtils;
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700213 private SaveAndFinishWorker mSaveAndFinishWorker;
Jim Miller17e9e192010-12-07 20:41:41 -0800214 private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
215 private ChooseLockSettingsHelper mChooseLockSettingsHelper;
Maurice Lam62c0c3c2017-07-10 18:15:10 -0700216 protected Stage mUiStage = Stage.Introduction;
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100217 private PasswordRequirementAdapter mPasswordRequirementAdapter;
Maurice Lam8df71732017-05-18 20:42:58 -0700218 private GlifLayout mLayout;
Maurice Lam562e5392017-06-27 17:38:06 -0700219 protected boolean mForFingerprint;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700220 protected boolean mForFace;
Paul Lawrence1f8fb0f2015-08-12 13:49:34 -0700221
Rubin Xu010116a2019-09-11 17:36:37 +0100222 private LockscreenCredential mFirstPassword;
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100223 private RecyclerView mPasswordRestrictionView;
Maurice Lamedb39442017-04-27 18:54:33 -0700224 protected boolean mIsAlphaMode;
pastychang76ad11c2019-01-18 14:28:27 +0800225 protected FooterButton mSkipOrClearButton;
226 private FooterButton mNextButton;
Maurice Lam3eb4c832017-08-02 20:11:28 -0700227 private TextView mMessage;
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100228
Tony Mak9ba765b2016-08-02 17:09:53 +0100229 private TextChangedHandler mTextChangedHandler;
230
Jim Miller17e9e192010-12-07 20:41:41 -0800231 private static final int CONFIRM_EXISTING_REQUEST = 58;
232 static final int RESULT_FINISHED = RESULT_FIRST_USER;
Amith Yamasani552bc612011-10-07 13:58:39 -0700233
Jim Miller00d24762009-12-22 19:04:57 -0800234 /**
Jim Miller17e9e192010-12-07 20:41:41 -0800235 * Keep track internally of where the user is in choosing a pattern.
Jim Miller00d24762009-12-22 19:04:57 -0800236 */
Jim Miller17e9e192010-12-07 20:41:41 -0800237 protected enum Stage {
Jim Miller00d24762009-12-22 19:04:57 -0800238
Maurice Lamb49526e2017-05-31 17:55:43 -0700239 Introduction(
Kevin Chyn81dc0292018-06-28 14:59:38 -0700240 R.string.lockpassword_choose_your_screen_lock_header, // password
Maurice Lamb49526e2017-05-31 17:55:43 -0700241 R.string.lockpassword_choose_your_password_header_for_fingerprint,
Kevin Chyn81dc0292018-06-28 14:59:38 -0700242 R.string.lockpassword_choose_your_password_header_for_face,
243 R.string.lockpassword_choose_your_screen_lock_header, // pin
Maurice Lamb49526e2017-05-31 17:55:43 -0700244 R.string.lockpassword_choose_your_pin_header_for_fingerprint,
Kevin Chyn81dc0292018-06-28 14:59:38 -0700245 R.string.lockpassword_choose_your_pin_header_for_face,
246 R.string.lockpassword_choose_your_password_message, // added security message
247 R.string.lock_settings_picker_biometrics_added_security_message,
Maurice Lam3eb4c832017-08-02 20:11:28 -0700248 R.string.lockpassword_choose_your_pin_message,
Kevin Chyn81dc0292018-06-28 14:59:38 -0700249 R.string.lock_settings_picker_biometrics_added_security_message,
Maurice Lamc57b19d2017-06-23 19:15:06 -0700250 R.string.next_label),
Jim Miller00d24762009-12-22 19:04:57 -0800251
Maurice Lamb49526e2017-05-31 17:55:43 -0700252 NeedToConfirm(
253 R.string.lockpassword_confirm_your_password_header,
254 R.string.lockpassword_confirm_your_password_header,
Kevin Chyn81dc0292018-06-28 14:59:38 -0700255 R.string.lockpassword_confirm_your_password_header,
256 R.string.lockpassword_confirm_your_pin_header,
Maurice Lamb49526e2017-05-31 17:55:43 -0700257 R.string.lockpassword_confirm_your_pin_header,
Jim Miller17e9e192010-12-07 20:41:41 -0800258 R.string.lockpassword_confirm_your_pin_header,
Maurice Lam3eb4c832017-08-02 20:11:28 -0700259 0,
260 0,
261 0,
262 0,
Maurice Lamac8024e2017-10-18 16:16:35 -0700263 R.string.lockpassword_confirm_label),
Konstantin Lopyrev57fbf692010-05-27 16:01:41 -0700264
Maurice Lamb49526e2017-05-31 17:55:43 -0700265 ConfirmWrong(
266 R.string.lockpassword_confirm_passwords_dont_match,
267 R.string.lockpassword_confirm_passwords_dont_match,
Kevin Chyn81dc0292018-06-28 14:59:38 -0700268 R.string.lockpassword_confirm_passwords_dont_match,
269 R.string.lockpassword_confirm_pins_dont_match,
Maurice Lamb49526e2017-05-31 17:55:43 -0700270 R.string.lockpassword_confirm_pins_dont_match,
Jim Miller17e9e192010-12-07 20:41:41 -0800271 R.string.lockpassword_confirm_pins_dont_match,
Maurice Lam3eb4c832017-08-02 20:11:28 -0700272 0,
273 0,
274 0,
275 0,
Kevin Chynd7b4b1b2018-02-28 17:28:15 -0800276 R.string.lockpassword_confirm_label);
Konstantin Lopyrev57fbf692010-05-27 16:01:41 -0700277
Kevin Chyn81dc0292018-06-28 14:59:38 -0700278 Stage(int hintInAlpha, int hintInAlphaForFingerprint, int hintInAlphaForFace,
279 int hintInNumeric, int hintInNumericForFingerprint, int hintInNumericForFace,
280 int messageInAlpha, int messageInAlphaForBiometrics,
281 int messageInNumeric, int messageInNumericForBiometrics,
Maurice Lam3eb4c832017-08-02 20:11:28 -0700282 int nextButtonText) {
Jim Miller17e9e192010-12-07 20:41:41 -0800283 this.alphaHint = hintInAlpha;
Maurice Lamb49526e2017-05-31 17:55:43 -0700284 this.alphaHintForFingerprint = hintInAlphaForFingerprint;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700285 this.alphaHintForFace = hintInAlphaForFace;
286
Jim Miller17e9e192010-12-07 20:41:41 -0800287 this.numericHint = hintInNumeric;
Maurice Lamb49526e2017-05-31 17:55:43 -0700288 this.numericHintForFingerprint = hintInNumericForFingerprint;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700289 this.numericHintForFace = hintInNumericForFace;
290
Maurice Lam3eb4c832017-08-02 20:11:28 -0700291 this.alphaMessage = messageInAlpha;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700292 this.alphaMessageForBiometrics = messageInAlphaForBiometrics;
Maurice Lam3eb4c832017-08-02 20:11:28 -0700293 this.numericMessage = messageInNumeric;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700294 this.numericMessageForBiometrics = messageInNumericForBiometrics;
Jim Miller17e9e192010-12-07 20:41:41 -0800295 this.buttonText = nextButtonText;
Jim Millerbbb4afa2010-04-08 19:40:19 -0700296 }
Jim Miller17e9e192010-12-07 20:41:41 -0800297
Kevin Chyn81dc0292018-06-28 14:59:38 -0700298 public static final int TYPE_NONE = 0;
299 public static final int TYPE_FINGERPRINT = 1;
300 public static final int TYPE_FACE = 2;
301
302 // Password
Jim Miller17e9e192010-12-07 20:41:41 -0800303 public final int alphaHint;
Maurice Lamb49526e2017-05-31 17:55:43 -0700304 public final int alphaHintForFingerprint;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700305 public final int alphaHintForFace;
306
307 // PIN
Jim Miller17e9e192010-12-07 20:41:41 -0800308 public final int numericHint;
Maurice Lamb49526e2017-05-31 17:55:43 -0700309 public final int numericHintForFingerprint;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700310 public final int numericHintForFace;
311
Maurice Lam3eb4c832017-08-02 20:11:28 -0700312 public final int alphaMessage;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700313 public final int alphaMessageForBiometrics;
Maurice Lam3eb4c832017-08-02 20:11:28 -0700314 public final int numericMessage;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700315 public final int numericMessageForBiometrics;
Jim Miller17e9e192010-12-07 20:41:41 -0800316 public final int buttonText;
Maurice Lamb49526e2017-05-31 17:55:43 -0700317
Kevin Chyn81dc0292018-06-28 14:59:38 -0700318 public @StringRes int getHint(boolean isAlpha, int type) {
Maurice Lamb49526e2017-05-31 17:55:43 -0700319 if (isAlpha) {
Kevin Chyn81dc0292018-06-28 14:59:38 -0700320 if (type == TYPE_FINGERPRINT) {
321 return alphaHintForFingerprint;
322 } else if (type == TYPE_FACE) {
323 return alphaHintForFace;
324 } else {
325 return alphaHint;
326 }
Maurice Lamb49526e2017-05-31 17:55:43 -0700327 } else {
Kevin Chyn81dc0292018-06-28 14:59:38 -0700328 if (type == TYPE_FINGERPRINT) {
329 return numericHintForFingerprint;
330 } else if (type == TYPE_FACE) {
331 return numericHintForFace;
332 } else {
333 return numericHint;
334 }
Maurice Lamb49526e2017-05-31 17:55:43 -0700335 }
336 }
Maurice Lam3eb4c832017-08-02 20:11:28 -0700337
Kevin Chyn81dc0292018-06-28 14:59:38 -0700338 public @StringRes int getMessage(boolean isAlpha, int type) {
Maurice Lam3eb4c832017-08-02 20:11:28 -0700339 if (isAlpha) {
Kevin Chyn81dc0292018-06-28 14:59:38 -0700340 return type != TYPE_NONE ? alphaMessageForBiometrics : alphaMessage;
Maurice Lam3eb4c832017-08-02 20:11:28 -0700341 } else {
Kevin Chyn81dc0292018-06-28 14:59:38 -0700342 return type != TYPE_NONE ? numericMessageForBiometrics : numericMessage;
Maurice Lam3eb4c832017-08-02 20:11:28 -0700343 }
344 }
Jim Miller00d24762009-12-22 19:04:57 -0800345 }
Jim Miller00d24762009-12-22 19:04:57 -0800346
Jim Miller17e9e192010-12-07 20:41:41 -0800347 // required constructor for fragments
348 public ChooseLockPasswordFragment() {
Jim Miller2f9dbcb2010-02-09 19:08:02 -0800349
Jim Miller17e9e192010-12-07 20:41:41 -0800350 }
Jim Miller2f9dbcb2010-02-09 19:08:02 -0800351
Jim Miller17e9e192010-12-07 20:41:41 -0800352 @Override
353 public void onCreate(Bundle savedInstanceState) {
354 super.onCreate(savedInstanceState);
355 mLockPatternUtils = new LockPatternUtils(getActivity());
356 Intent intent = getActivity().getIntent();
Amith Yamasani66026772013-09-25 14:05:33 -0700357 if (!(getActivity() instanceof ChooseLockPassword)) {
358 throw new SecurityException("Fragment contained in wrong activity");
359 }
Clara Bayarrife432e82015-10-12 12:07:02 +0100360 // Only take this argument into account if it belongs to the current profile.
Benjamin Franz194300d2016-01-13 12:16:25 +0000361 mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras());
Maurice Lamb49526e2017-05-31 17:55:43 -0700362 mForFingerprint = intent.getBooleanExtra(
363 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700364 mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100365 mMinComplexity = intent.getIntExtra(
Bernard Chau92db5bf2018-12-17 18:03:24 +0000366 EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
Bernard Chau92db5bf2018-12-17 18:03:24 +0000367
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100368 mRequestedQuality = intent.getIntExtra(
369 LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC);
370
371 mMinMetrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId);
Jim Miller17e9e192010-12-07 20:41:41 -0800372 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
Adrian Roos62775bf2016-01-28 13:23:53 -0800373
374 if (intent.getBooleanExtra(
375 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
376 SaveAndFinishWorker w = new SaveAndFinishWorker();
377 final boolean required = getActivity().getIntent().getBooleanExtra(
378 EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
Rubin Xu010116a2019-09-11 17:36:37 +0100379 LockscreenCredential currentCredential = intent.getParcelableExtra(
Adrian Roos62775bf2016-01-28 13:23:53 -0800380 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
Rich Canningsb27c4302019-02-19 13:15:30 -0800381
Adrian Roos62775bf2016-01-28 13:23:53 -0800382 w.setBlocking(true);
383 w.setListener(this);
Rich Canningsb27c4302019-02-19 13:15:30 -0800384 w.start(mChooseLockSettingsHelper.utils(), required, false, 0,
Rubin Xu010116a2019-09-11 17:36:37 +0100385 currentCredential, currentCredential, mUserId);
Adrian Roos62775bf2016-01-28 13:23:53 -0800386 }
Tony Mak9ba765b2016-08-02 17:09:53 +0100387 mTextChangedHandler = new TextChangedHandler();
Jim Miller17e9e192010-12-07 20:41:41 -0800388 }
Jim Miller2f9dbcb2010-02-09 19:08:02 -0800389
Jim Miller17e9e192010-12-07 20:41:41 -0800390 @Override
391 public View onCreateView(LayoutInflater inflater, ViewGroup container,
392 Bundle savedInstanceState) {
Maurice Lam44f27362016-07-08 18:38:48 -0700393 return inflater.inflate(R.layout.choose_lock_password, container, false);
Maurice Lam6b19fa92014-11-25 19:25:56 -0800394 }
Jim Miller2f9dbcb2010-02-09 19:08:02 -0800395
Maurice Lam6b19fa92014-11-25 19:25:56 -0800396 @Override
397 public void onViewCreated(View view, Bundle savedInstanceState) {
398 super.onViewCreated(view, savedInstanceState);
Jim Miller2f9dbcb2010-02-09 19:08:02 -0800399
Maurice Lam8df71732017-05-18 20:42:58 -0700400 mLayout = (GlifLayout) view;
401
Maurice Lamedb39442017-04-27 18:54:33 -0700402 // Make the password container consume the optical insets so the edit text is aligned
403 // with the sides of the parent visually.
404 ViewGroup container = view.findViewById(R.id.password_container);
405 container.setOpticalInsets(Insets.NONE);
406
pastychang9bdb59a2019-01-21 09:49:15 +0800407 final FooterBarMixin mixin = mLayout.getMixin(FooterBarMixin.class);
pastychang76ad11c2019-01-18 14:28:27 +0800408 mixin.setSecondaryButton(
409 new FooterButton.Builder(getActivity())
410 .setText(R.string.lockpassword_clear_label)
411 .setListener(this::onSkipOrClearButtonClick)
412 .setButtonType(FooterButton.ButtonType.SKIP)
413 .setTheme(R.style.SudGlifButton_Secondary)
414 .build()
415 );
416 mixin.setPrimaryButton(
417 new FooterButton.Builder(getActivity())
418 .setText(R.string.next_label)
419 .setListener(this::onNextButtonClick)
420 .setButtonType(FooterButton.ButtonType.NEXT)
421 .setTheme(R.style.SudGlifButton_Primary)
422 .build()
423 );
424 mSkipOrClearButton = mixin.getSecondaryButton();
425 mNextButton = mixin.getPrimaryButton();
Maurice Lam3eb4c832017-08-02 20:11:28 -0700426
pastychangfa68ec42019-04-12 16:22:17 +0800427 mMessage = view.findViewById(R.id.sud_layout_description);
Maurice Lamd7935902017-06-21 17:09:33 -0700428 if (mForFingerprint) {
Ajay Nadathur7af28ec2017-07-21 15:11:21 -0700429 mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_fingerprint_header));
Kevin Chyn81dc0292018-06-28 14:59:38 -0700430 } else if (mForFace) {
431 mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_face_header));
Maurice Lamd7935902017-06-21 17:09:33 -0700432 }
433
Jim Miller17e9e192010-12-07 20:41:41 -0800434 mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
435 || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality
436 || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality;
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100437
438 setupPasswordRequirementsView(view);
439
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100440 mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
Tarandeep Singhb0bcbed2017-07-14 13:22:07 -0700441 mPasswordEntry = view.findViewById(R.id.password_entry);
Jim Miller17e9e192010-12-07 20:41:41 -0800442 mPasswordEntry.setOnEditorActionListener(this);
443 mPasswordEntry.addTextChangedListener(this);
Tony Mak9c26c9d2016-07-01 13:55:47 +0100444 mPasswordEntry.requestFocus();
Xiyuan Xiaf2c2c192015-05-15 13:37:04 -0700445 mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
Jim Miller17e9e192010-12-07 20:41:41 -0800446
Jim Miller9757e302010-12-17 18:23:23 -0800447 final Activity activity = getActivity();
Jim Miller17e9e192010-12-07 20:41:41 -0800448
Jim Miller2e28ace2010-12-15 10:07:16 -0800449 int currentType = mPasswordEntry.getInputType();
450 mPasswordEntry.setInputType(mIsAlphaMode ? currentType
Jim Miller3b46f492011-01-17 15:50:05 -0800451 : (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
joshmccloskeyfc397f72019-08-27 12:01:30 -0700452 if (mIsAlphaMode) {
453 mPasswordEntry.setContentDescription(
454 getString(R.string.unlock_set_unlock_password_title));
455 } else {
456 mPasswordEntry.setContentDescription(
457 getString(R.string.unlock_set_unlock_pin_title));
458 }
Andrew Sappersteinccbb4cf2017-07-06 14:30:28 -0700459 // Can't set via XML since setInputType resets the fontFamily to null
460 mPasswordEntry.setTypeface(Typeface.create(
461 getContext().getString(com.android.internal.R.string.config_headlineFontFamily),
462 Typeface.NORMAL));
Jim Miller2e28ace2010-12-15 10:07:16 -0800463
Jim Miller17e9e192010-12-07 20:41:41 -0800464 Intent intent = getActivity().getIntent();
Andres Morales6609b0c2015-04-12 15:38:25 -0700465 final boolean confirmCredentials = intent.getBooleanExtra(
466 ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
Rubin Xu010116a2019-09-11 17:36:37 +0100467 mCurrentCredential = intent.getParcelableExtra(
Rich Canningsb27c4302019-02-19 13:15:30 -0800468 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
Andres Morales6609b0c2015-04-12 15:38:25 -0700469 mHasChallenge = intent.getBooleanExtra(
470 ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
471 mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
Jim Miller17e9e192010-12-07 20:41:41 -0800472 if (savedInstanceState == null) {
473 updateStage(Stage.Introduction);
474 if (confirmCredentials) {
475 mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
Clara Bayarrife432e82015-10-12 12:07:02 +0100476 getString(R.string.unlock_set_unlock_launch_picker_title), true,
477 mUserId);
Jim Miller17e9e192010-12-07 20:41:41 -0800478 }
479 } else {
Rich Canningsb27c4302019-02-19 13:15:30 -0800480
Andres Moralesa0e12362015-04-02 09:00:41 -0700481 // restore from previous state
Rubin Xu010116a2019-09-11 17:36:37 +0100482 mFirstPassword = savedInstanceState.getParcelable(KEY_FIRST_PASSWORD);
Jim Miller17e9e192010-12-07 20:41:41 -0800483 final String state = savedInstanceState.getString(KEY_UI_STAGE);
484 if (state != null) {
485 mUiStage = Stage.valueOf(state);
486 updateStage(mUiStage);
487 }
Andres Moralesa0e12362015-04-02 09:00:41 -0700488
Rubin Xu010116a2019-09-11 17:36:37 +0100489 if (mCurrentCredential == null) {
490 mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_CREDENTIAL);
Andres Moralesa0e12362015-04-02 09:00:41 -0700491 }
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700492
493 // Re-attach to the exiting worker if there is one.
494 mSaveAndFinishWorker = (SaveAndFinishWorker) getFragmentManager().findFragmentByTag(
495 FRAGMENT_TAG_SAVE_AND_FINISH);
Jim Miller17e9e192010-12-07 20:41:41 -0800496 }
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100497
Fabrice Di Meglio263bcc82014-01-17 19:17:58 -0800498 if (activity instanceof SettingsActivity) {
499 final SettingsActivity sa = (SettingsActivity) activity;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700500 int title = Stage.Introduction.getHint(mIsAlphaMode, getStageType());
Fabrice Di Meglio263bcc82014-01-17 19:17:58 -0800501 sa.setTitle(title);
Maurice Lam8df71732017-05-18 20:42:58 -0700502 mLayout.setHeaderText(title);
Jim Miller9757e302010-12-17 18:23:23 -0800503 }
Jim Miller17e9e192010-12-07 20:41:41 -0800504 }
505
pastychang7a083f82019-03-26 16:09:34 +0800506 protected int getStageType() {
Kevin Chyn81dc0292018-06-28 14:59:38 -0700507 return mForFingerprint ? Stage.TYPE_FINGERPRINT :
508 mForFace ? Stage.TYPE_FACE :
509 Stage.TYPE_NONE;
510 }
511
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100512 private void setupPasswordRequirementsView(View view) {
Pavel Grafov5f139102018-05-04 17:09:28 +0100513 mPasswordRestrictionView = view.findViewById(R.id.password_requirements_view);
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100514 mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
515 mPasswordRequirementAdapter = new PasswordRequirementAdapter();
516 mPasswordRestrictionView.setAdapter(mPasswordRequirementAdapter);
517 }
518
Jim Miller17e9e192010-12-07 20:41:41 -0800519 @Override
Fan Zhang65076132016-08-08 10:25:13 -0700520 public int getMetricsCategory() {
Fan Zhang31b21002019-01-16 13:49:47 -0800521 return SettingsEnums.CHOOSE_LOCK_PASSWORD;
Chris Wren8a963ba2015-03-20 10:29:14 -0400522 }
523
524 @Override
Jim Miller17e9e192010-12-07 20:41:41 -0800525 public void onResume() {
526 super.onResume();
Jim Miller122b6c82010-02-10 19:53:58 -0800527 updateStage(mUiStage);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700528 if (mSaveAndFinishWorker != null) {
529 mSaveAndFinishWorker.setListener(this);
530 } else {
Tony Mak9c26c9d2016-07-01 13:55:47 +0100531 mPasswordEntry.requestFocus();
Tarandeep Singhb0bcbed2017-07-14 13:22:07 -0700532 mPasswordEntry.scheduleShowSoftInput();
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700533 }
Jim Miller122b6c82010-02-10 19:53:58 -0800534 }
Jim Miller00d24762009-12-22 19:04:57 -0800535
Jim Miller17e9e192010-12-07 20:41:41 -0800536 @Override
Amith Yamasani552bc612011-10-07 13:58:39 -0700537 public void onPause() {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700538 if (mSaveAndFinishWorker != null) {
539 mSaveAndFinishWorker.setListener(null);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700540 }
Amith Yamasani552bc612011-10-07 13:58:39 -0700541 super.onPause();
542 }
543
544 @Override
Jim Miller17e9e192010-12-07 20:41:41 -0800545 public void onSaveInstanceState(Bundle outState) {
546 super.onSaveInstanceState(outState);
547 outState.putString(KEY_UI_STAGE, mUiStage.name());
Rubin Xu010116a2019-09-11 17:36:37 +0100548 outState.putParcelable(KEY_FIRST_PASSWORD, mFirstPassword);
549 outState.putParcelable(KEY_CURRENT_CREDENTIAL, mCurrentCredential);
Jim Miller00d24762009-12-22 19:04:57 -0800550 }
Jim Miller00d24762009-12-22 19:04:57 -0800551
Jim Miller17e9e192010-12-07 20:41:41 -0800552 @Override
553 public void onActivityResult(int requestCode, int resultCode,
554 Intent data) {
555 super.onActivityResult(requestCode, resultCode, data);
556 switch (requestCode) {
557 case CONFIRM_EXISTING_REQUEST:
558 if (resultCode != Activity.RESULT_OK) {
559 getActivity().setResult(RESULT_FINISHED);
560 getActivity().finish();
Andres Moralesa0e12362015-04-02 09:00:41 -0700561 } else {
Rubin Xu010116a2019-09-11 17:36:37 +0100562 mCurrentCredential = data.getParcelableExtra(
Andres Moralesa0e12362015-04-02 09:00:41 -0700563 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
Jim Miller17e9e192010-12-07 20:41:41 -0800564 }
565 break;
Jim Miller122b6c82010-02-10 19:53:58 -0800566 }
567 }
Jim Miller122b6c82010-02-10 19:53:58 -0800568
Maurice Lamecd2b7b2014-12-01 10:41:49 -0800569 protected Intent getRedactionInterstitialIntent(Context context) {
Clara Bayarrif6077f42016-01-25 17:21:24 +0000570 return RedactionInterstitial.createStartIntent(context, mUserId);
Maurice Lamecd2b7b2014-12-01 10:41:49 -0800571 }
572
Jim Miller17e9e192010-12-07 20:41:41 -0800573 protected void updateStage(Stage stage) {
alanveef72c32012-10-03 17:10:50 -0700574 final Stage previousStage = mUiStage;
Jim Miller17e9e192010-12-07 20:41:41 -0800575 mUiStage = stage;
576 updateUi();
alanveef72c32012-10-03 17:10:50 -0700577
578 // If the stage changed, announce the header for accessibility. This
579 // is a no-op when accessibility is disabled.
580 if (previousStage != stage) {
Maurice Lam8df71732017-05-18 20:42:58 -0700581 mLayout.announceForAccessibility(mLayout.getHeaderText());
alanveef72c32012-10-03 17:10:50 -0700582 }
Jim Miller122b6c82010-02-10 19:53:58 -0800583 }
Jim Miller00d24762009-12-22 19:04:57 -0800584
Jim Miller17e9e192010-12-07 20:41:41 -0800585 /**
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100586 * Validates PIN/Password and returns the validation result and updates mValidationErrors
587 * and mPasswordReused to reflect validation results.
Bernard Chau92db5bf2018-12-17 18:03:24 +0000588 *
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100589 * @param credential credential the user typed in.
590 * @return whether password satisfies all the requirements.
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100591 */
Bernard Chau92db5bf2018-12-17 18:03:24 +0000592 @VisibleForTesting
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100593 boolean validatePassword(LockscreenCredential credential) {
Rubin Xu010116a2019-09-11 17:36:37 +0100594 final byte[] password = credential.getCredential();
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100595 mValidationErrors = PasswordMetrics.validatePassword(
596 mMinMetrics, mMinComplexity, !mIsAlphaMode, password);
597 if (mValidationErrors.isEmpty() && mLockPatternUtils.checkPasswordHistory(
598 password, getPasswordHistoryHashFactor(), mUserId)) {
599 mValidationErrors =
600 Collections.singletonList(new PasswordValidationError(RECENTLY_USED));
Jim Miller17e9e192010-12-07 20:41:41 -0800601 }
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100602 return mValidationErrors.isEmpty();
Jim Miller17e9e192010-12-07 20:41:41 -0800603 }
604
Rubin Xuc33e2a12018-03-30 20:51:24 +0100605 /**
606 * Lazily compute and return the history hash factor of the current user (mUserId), used for
607 * password history check.
608 */
609 private byte[] getPasswordHistoryHashFactor() {
610 if (mPasswordHistoryHashFactor == null) {
611 mPasswordHistoryHashFactor = mLockPatternUtils.getPasswordHistoryHashFactor(
Rubin Xu010116a2019-09-11 17:36:37 +0100612 mCurrentCredential != null ? mCurrentCredential
613 : LockscreenCredential.createNone(), mUserId);
Rubin Xuc33e2a12018-03-30 20:51:24 +0100614 }
615 return mPasswordHistoryHashFactor;
616 }
617
Paul Lawrencecff37ec2015-08-03 09:44:23 -0700618 public void handleNext() {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700619 if (mSaveAndFinishWorker != null) return;
Rich Canningsb27c4302019-02-19 13:15:30 -0800620 // TODO(b/120484642): This is a point of entry for passwords from the UI
Rubin Xu010116a2019-09-11 17:36:37 +0100621 final Editable passwordText = mPasswordEntry.getText();
622 if (TextUtils.isEmpty(passwordText)) {
Jim Miller17e9e192010-12-07 20:41:41 -0800623 return;
624 }
Rubin Xu010116a2019-09-11 17:36:37 +0100625 mChosenPassword = mIsAlphaMode ? LockscreenCredential.createPassword(passwordText)
626 : LockscreenCredential.createPin(passwordText);
Jim Miller17e9e192010-12-07 20:41:41 -0800627 if (mUiStage == Stage.Introduction) {
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100628 if (validatePassword(mChosenPassword)) {
Rubin Xu010116a2019-09-11 17:36:37 +0100629 mFirstPassword = mChosenPassword;
Jim Miller17e9e192010-12-07 20:41:41 -0800630 mPasswordEntry.setText("");
alanveef72c32012-10-03 17:10:50 -0700631 updateStage(Stage.NeedToConfirm);
Rich Canningsb27c4302019-02-19 13:15:30 -0800632 } else {
Rubin Xu010116a2019-09-11 17:36:37 +0100633 mChosenPassword.zeroize();
Jim Miller17e9e192010-12-07 20:41:41 -0800634 }
635 } else if (mUiStage == Stage.NeedToConfirm) {
Rubin Xu010116a2019-09-11 17:36:37 +0100636 if (mChosenPassword.equals(mFirstPassword)) {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700637 startSaveAndFinish();
Jim Miller17e9e192010-12-07 20:41:41 -0800638 } else {
Jim Miller17e9e192010-12-07 20:41:41 -0800639 CharSequence tmp = mPasswordEntry.getText();
640 if (tmp != null) {
641 Selection.setSelection((Spannable) tmp, 0, tmp.length());
642 }
alanveef72c32012-10-03 17:10:50 -0700643 updateStage(Stage.ConfirmWrong);
Rubin Xu010116a2019-09-11 17:36:37 +0100644 mChosenPassword.zeroize();
Jim Miller17e9e192010-12-07 20:41:41 -0800645 }
646 }
Jim Miller17e9e192010-12-07 20:41:41 -0800647 }
648
Maurice Lamaf103b42014-12-03 15:17:46 -0800649 protected void setNextEnabled(boolean enabled) {
650 mNextButton.setEnabled(enabled);
651 }
652
653 protected void setNextText(int text) {
pastychang76ad11c2019-01-18 14:28:27 +0800654 mNextButton.setText(getActivity(), text);
Maurice Lamaf103b42014-12-03 15:17:46 -0800655 }
656
pastychang76ad11c2019-01-18 14:28:27 +0800657 protected void onSkipOrClearButtonClick(View view) {
658 mPasswordEntry.setText("");
659 }
Jim Miller17e9e192010-12-07 20:41:41 -0800660
pastychang76ad11c2019-01-18 14:28:27 +0800661 protected void onNextButtonClick(View view) {
662 handleNext();
Jim Miller17e9e192010-12-07 20:41:41 -0800663 }
664
Jim Miller17e9e192010-12-07 20:41:41 -0800665 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Jim Miller74b1e0a2011-04-15 18:52:31 -0700666 // Check if this was the result of hitting the enter or "done" key
667 if (actionId == EditorInfo.IME_NULL
668 || actionId == EditorInfo.IME_ACTION_DONE
669 || actionId == EditorInfo.IME_ACTION_NEXT) {
Jim Miller17e9e192010-12-07 20:41:41 -0800670 handleNext();
671 return true;
672 }
673 return false;
674 }
675
676 /**
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100677 * @param errorCode error code returned from password validation.
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100678 * @return an array of messages describing the error, important messages come first.
679 */
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100680 String[] convertErrorCodeToMessages() {
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100681 List<String> messages = new ArrayList<>();
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100682 for (PasswordValidationError error : mValidationErrors) {
683 switch (error.errorCode) {
684 case CONTAINS_INVALID_CHARACTERS:
685 messages.add(getString(R.string.lockpassword_illegal_character));
686 break;
687 case NOT_ENOUGH_UPPER_CASE:
688 messages.add(getResources().getQuantityString(
689 R.plurals.lockpassword_password_requires_uppercase,
690 error.requirement, error.requirement));
691 break;
692 case NOT_ENOUGH_LOWER_CASE:
693 messages.add(getResources().getQuantityString(
694 R.plurals.lockpassword_password_requires_lowercase,
695 error.requirement, error.requirement));
696 break;
697 case NOT_ENOUGH_LETTERS:
698 messages.add(getResources().getQuantityString(
699 R.plurals.lockpassword_password_requires_letters,
700 error.requirement, error.requirement));
701 break;
702 case NOT_ENOUGH_DIGITS:
703 messages.add(getResources().getQuantityString(
704 R.plurals.lockpassword_password_requires_numeric,
705 error.requirement, error.requirement));
706 break;
707 case NOT_ENOUGH_SYMBOLS:
708 messages.add(getResources().getQuantityString(
709 R.plurals.lockpassword_password_requires_symbols,
710 error.requirement, error.requirement));
711 break;
712 case NOT_ENOUGH_NON_LETTER:
713 messages.add(getResources().getQuantityString(
714 R.plurals.lockpassword_password_requires_nonletter,
715 error.requirement, error.requirement));
716 break;
717 case NOT_ENOUGH_NON_DIGITS:
718 messages.add(getResources().getQuantityString(
719 R.plurals.lockpassword_password_requires_nonnumerical,
720 error.requirement, error.requirement));
721 break;
722 case TOO_SHORT:
723 messages.add(getResources().getQuantityString(
724 mIsAlphaMode
725 ? R.plurals.lockpassword_password_too_short
726 : R.plurals.lockpassword_pin_too_short,
727 error.requirement, error.requirement));
728 break;
729 case TOO_LONG:
730 messages.add(getResources().getQuantityString(
731 mIsAlphaMode
732 ? R.plurals.lockpassword_password_too_long
733 : R.plurals.lockpassword_pin_too_long,
734 error.requirement + 1, error.requirement + 1));
735 break;
736 case CONTAINS_SEQUENCE:
737 messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
738 break;
739 case RECENTLY_USED:
740 messages.add(getString(mIsAlphaMode
741 ? R.string.lockpassword_password_recently_used
742 : R.string.lockpassword_pin_recently_used));
743 break;
744 default:
745 Log.wtf(TAG, "unknown error validating password: " + error);
746 }
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100747 }
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100748
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100749 return messages.toArray(new String[0]);
Tony Mak9ba765b2016-08-02 17:09:53 +0100750 }
751
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100752 /**
Jim Miller17e9e192010-12-07 20:41:41 -0800753 * Update the hint based on current Stage and length of password entry
754 */
Maurice Lam62c0c3c2017-07-10 18:15:10 -0700755 protected void updateUi() {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700756 final boolean canInput = mSaveAndFinishWorker == null;
Rubin Xu010116a2019-09-11 17:36:37 +0100757
758 LockscreenCredential password = mIsAlphaMode
759 ? LockscreenCredential.createPasswordOrNone(mPasswordEntry.getText())
760 : LockscreenCredential.createPinOrNone(mPasswordEntry.getText());
761 final int length = password.size();
Maurice Lam163dee92015-05-19 17:27:12 -0700762 if (mUiStage == Stage.Introduction) {
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100763 mPasswordRestrictionView.setVisibility(View.VISIBLE);
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100764 final boolean passwordCompliant = validatePassword(password);
765 String[] messages = convertErrorCodeToMessages();
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100766 // Update the fulfillment of requirements.
767 mPasswordRequirementAdapter.setRequirements(messages);
768 // Enable/Disable the next button accordingly.
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100769 setNextEnabled(passwordCompliant);
Jim Miller17e9e192010-12-07 20:41:41 -0800770 } else {
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100771 // Hide password requirement view when we are just asking user to confirm the pw.
772 mPasswordRestrictionView.setVisibility(View.GONE);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700773 setHeaderText(getString(mUiStage.getHint(mIsAlphaMode, getStageType())));
Pavel Grafov69cac2c2019-08-07 13:21:53 +0100774 setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
pastychang76ad11c2019-01-18 14:28:27 +0800775 mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0));
Jim Miller122b6c82010-02-10 19:53:58 -0800776 }
Kevin Chyn81dc0292018-06-28 14:59:38 -0700777 int message = mUiStage.getMessage(mIsAlphaMode, getStageType());
Maurice Lam3eb4c832017-08-02 20:11:28 -0700778 if (message != 0) {
779 mMessage.setVisibility(View.VISIBLE);
780 mMessage.setText(message);
781 } else {
782 mMessage.setVisibility(View.INVISIBLE);
783 }
Ajay Nadathurbe2246b2017-08-02 14:46:26 -0700784
Maurice Lamaf103b42014-12-03 15:17:46 -0800785 setNextText(mUiStage.buttonText);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700786 mPasswordEntryInputDisabler.setInputEnabled(canInput);
Rubin Xu010116a2019-09-11 17:36:37 +0100787 password.zeroize();
Jim Miller122b6c82010-02-10 19:53:58 -0800788 }
Jim Miller122b6c82010-02-10 19:53:58 -0800789
pastychang382d34d2018-12-24 17:16:14 +0800790 protected int toVisibility(boolean visibleOrGone) {
Ajay Nadathurbe2246b2017-08-02 14:46:26 -0700791 return visibleOrGone ? View.VISIBLE : View.GONE;
792 }
793
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100794 private void setHeaderText(String text) {
795 // Only set the text if it is different than the existing one to avoid announcing again.
Maurice Lam8df71732017-05-18 20:42:58 -0700796 if (!TextUtils.isEmpty(mLayout.getHeaderText())
797 && mLayout.getHeaderText().toString().equals(text)) {
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100798 return;
799 }
Maurice Lam8df71732017-05-18 20:42:58 -0700800 mLayout.setHeaderText(text);
Tony Mak0bbcdcc2016-07-12 11:19:45 +0100801 }
802
Jim Miller17e9e192010-12-07 20:41:41 -0800803 public void afterTextChanged(Editable s) {
804 // Changing the text while error displayed resets to NeedToConfirm state
805 if (mUiStage == Stage.ConfirmWrong) {
806 mUiStage = Stage.NeedToConfirm;
807 }
Tony Mak9ba765b2016-08-02 17:09:53 +0100808 // Schedule the UI update.
809 mTextChangedHandler.notifyAfterTextChanged();
Jim Miller122b6c82010-02-10 19:53:58 -0800810 }
Jim Miller122b6c82010-02-10 19:53:58 -0800811
Jim Miller17e9e192010-12-07 20:41:41 -0800812 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Jim Miller122b6c82010-02-10 19:53:58 -0800813
Jim Miller17e9e192010-12-07 20:41:41 -0800814 }
Jim Miller122b6c82010-02-10 19:53:58 -0800815
Jim Miller17e9e192010-12-07 20:41:41 -0800816 public void onTextChanged(CharSequence s, int start, int before, int count) {
Jim Miller122b6c82010-02-10 19:53:58 -0800817
Jim Miller17e9e192010-12-07 20:41:41 -0800818 }
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700819
820 private void startSaveAndFinish() {
821 if (mSaveAndFinishWorker != null) {
822 Log.w(TAG, "startSaveAndFinish with an existing SaveAndFinishWorker.");
823 return;
824 }
825
826 mPasswordEntryInputDisabler.setInputEnabled(false);
827 setNextEnabled(false);
828
829 mSaveAndFinishWorker = new SaveAndFinishWorker();
Robin Lee5bb1e4f2016-01-27 17:21:00 +0000830 mSaveAndFinishWorker.setListener(this);
831
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700832 getFragmentManager().beginTransaction().add(mSaveAndFinishWorker,
833 FRAGMENT_TAG_SAVE_AND_FINISH).commit();
Robin Lee5bb1e4f2016-01-27 17:21:00 +0000834 getFragmentManager().executePendingTransactions();
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700835
836 final boolean required = getActivity().getIntent().getBooleanExtra(
837 EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
838 mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge,
Rubin Xu010116a2019-09-11 17:36:37 +0100839 mChosenPassword, mCurrentCredential, mUserId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700840 }
841
842 @Override
843 public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
844 getActivity().setResult(RESULT_FINISHED, resultData);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700845
Rich Canningsb27c4302019-02-19 13:15:30 -0800846 if (mChosenPassword != null) {
Rubin Xu010116a2019-09-11 17:36:37 +0100847 mChosenPassword.zeroize();
Rich Canningsb27c4302019-02-19 13:15:30 -0800848 }
Rubin Xu010116a2019-09-11 17:36:37 +0100849 if (mCurrentCredential != null) {
850 mCurrentCredential.zeroize();
Rich Canningsb27c4302019-02-19 13:15:30 -0800851 }
Rubin Xu010116a2019-09-11 17:36:37 +0100852 if (mFirstPassword != null) {
853 mFirstPassword.zeroize();
Rich Canningsb27c4302019-02-19 13:15:30 -0800854 }
855
856 mPasswordEntry.setText("");
857
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700858 if (!wasSecureBefore) {
859 Intent intent = getRedactionInterstitialIntent(getActivity());
860 if (intent != null) {
861 startActivity(intent);
862 }
863 }
Udam Saini686ae492016-02-02 17:02:29 -0800864 getActivity().finish();
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700865 }
Tony Mak9ba765b2016-08-02 17:09:53 +0100866
867 class TextChangedHandler extends Handler {
868 private static final int ON_TEXT_CHANGED = 1;
869 private static final int DELAY_IN_MILLISECOND = 100;
870
871 /**
872 * With the introduction of delay, we batch processing the text changed event to reduce
873 * unnecessary UI updates.
874 */
875 private void notifyAfterTextChanged() {
876 removeMessages(ON_TEXT_CHANGED);
877 sendEmptyMessageDelayed(ON_TEXT_CHANGED, DELAY_IN_MILLISECOND);
878 }
879
880 @Override
881 public void handleMessage(Message msg) {
Doris Lingf958f2e2016-08-24 17:17:52 -0700882 if (getActivity() == null) {
883 return;
884 }
Tony Mak9ba765b2016-08-02 17:09:53 +0100885 if (msg.what == ON_TEXT_CHANGED) {
886 updateUi();
887 }
888 }
889 }
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700890 }
891
Clara Bayarri77c43452016-06-23 11:11:42 +0100892 public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700893
Rubin Xu010116a2019-09-11 17:36:37 +0100894 private LockscreenCredential mChosenPassword;
895 private LockscreenCredential mCurrentCredential;
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700896
897 public void start(LockPatternUtils utils, boolean required,
898 boolean hasChallenge, long challenge,
Rubin Xu010116a2019-09-11 17:36:37 +0100899 LockscreenCredential chosenPassword, LockscreenCredential currentCredential,
900 int userId) {
Clara Bayarrib8a22e42015-12-18 16:40:18 +0000901 prepare(utils, required, hasChallenge, challenge, userId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700902
903 mChosenPassword = chosenPassword;
Rubin Xu010116a2019-09-11 17:36:37 +0100904 mCurrentCredential = currentCredential != null ? currentCredential
905 : LockscreenCredential.createNone();
Clara Bayarrife432e82015-10-12 12:07:02 +0100906 mUserId = userId;
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700907
908 start();
909 }
910
911 @Override
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +0000912 protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
Rubin Xu010116a2019-09-11 17:36:37 +0100913 final boolean success = mUtils.setLockCredential(
914 mChosenPassword, mCurrentCredential, mUserId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700915 Intent result = null;
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +0000916 if (success && mHasChallenge) {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700917 byte[] token;
918 try {
Rubin Xu010116a2019-09-11 17:36:37 +0100919 token = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700920 } catch (RequestThrottledException e) {
921 token = null;
922 }
923
924 if (token == null) {
925 Log.e(TAG, "critical: no token returned for known good password.");
926 }
927
928 result = new Intent();
929 result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
930 }
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +0000931 return Pair.create(success, result);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700932 }
Jim Miller122b6c82010-02-10 19:53:58 -0800933 }
Jim Miller00d24762009-12-22 19:04:57 -0800934}