blob: b5670cacc43e15177c29f5de7a09b6f7c775d21e [file] [log] [blame]
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001/*
2 * Copyright (C) 2007 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;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080018
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080019import android.app.Activity;
Fan Zhang31b21002019-01-16 13:49:47 -080020import android.app.settings.SettingsEnums;
Jim Miller0698a212014-10-16 19:49:07 -070021import android.content.Context;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080022import android.content.Intent;
Jyun LuoLai11960ce2018-03-15 14:11:30 +080023import android.content.res.ColorStateList;
Maurice Lam9990f392017-06-28 15:06:09 -070024import android.content.res.Resources.Theme;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080025import android.os.Bundle;
Andres Morales91e6c492015-05-15 15:20:33 -070026import android.util.Log;
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +000027import android.util.Pair;
Jyun LuoLai11960ce2018-03-15 14:11:30 +080028import android.util.TypedValue;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080029import android.view.KeyEvent;
Jim Miller17e9e192010-12-07 20:41:41 -080030import android.view.LayoutInflater;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080031import android.view.View;
Jim Miller17e9e192010-12-07 20:41:41 -080032import android.view.ViewGroup;
jackqdyulei011f0db2016-10-21 10:50:34 -070033import android.widget.ScrollView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080034import android.widget.TextView;
35
Fan Zhang23f8d592018-08-28 15:11:40 -070036import androidx.fragment.app.Fragment;
37
Rubin Xu010116a2019-09-11 17:36:37 +010038import com.android.internal.annotations.VisibleForTesting;
Jason Monk39b46742015-09-10 15:52:51 -040039import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
40import com.android.internal.widget.LockPatternUtils;
41import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
42import com.android.internal.widget.LockPatternView;
43import com.android.internal.widget.LockPatternView.Cell;
44import com.android.internal.widget.LockPatternView.DisplayMode;
Rubin Xu010116a2019-09-11 17:36:37 +010045import com.android.internal.widget.LockscreenCredential;
Maurice Lam2eb170c2017-04-28 16:18:47 -070046import com.android.settings.EncryptionInterstitial;
47import com.android.settings.R;
48import com.android.settings.SettingsActivity;
Maurice Lam9990f392017-06-28 15:06:09 -070049import com.android.settings.SetupWizardUtils;
Maurice Lam2eb170c2017-04-28 16:18:47 -070050import com.android.settings.Utils;
Doris Ling72489722017-11-16 11:03:40 -080051import com.android.settings.core.InstrumentedFragment;
Jason Monk39b46742015-09-10 15:52:51 -040052import com.android.settings.notification.RedactionInterstitial;
Maurice Lam2eb170c2017-04-28 16:18:47 -070053
Jason Monk39b46742015-09-10 15:52:51 -040054import com.google.android.collect.Lists;
pastychang9bdb59a2019-01-21 09:49:15 +080055import com.google.android.setupcompat.template.FooterBarMixin;
56import com.google.android.setupcompat.template.FooterButton;
Pasty Changc1f86002018-12-11 02:22:55 +000057import com.google.android.setupdesign.GlifLayout;
Jason Monk39b46742015-09-10 15:52:51 -040058
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080059import java.util.Collections;
60import java.util.List;
61
62/**
63 * If the user has a lock pattern set already, makes them confirm the existing one.
64 *
65 * Then, prompts the user to choose a lock pattern:
66 * - prompts for initial pattern
67 * - asks for confirmation / restart
68 * - saves chosen password when confirmed
69 */
Fabrice Di Meglio263bcc82014-01-17 19:17:58 -080070public class ChooseLockPattern extends SettingsActivity {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080071 /**
72 * Used by the choose lock pattern wizard to indicate the wizard is
73 * finished, and each activity in the wizard should finish.
74 * <p>
75 * Previously, each activity in the wizard would finish itself after
76 * starting the next activity. However, this leads to broken 'Back'
77 * behavior. So, now an activity does not finish itself until it gets this
78 * result.
79 */
80 static final int RESULT_FINISHED = RESULT_FIRST_USER;
Jim Miller00d24762009-12-22 19:04:57 -080081
Andres Morales91e6c492015-05-15 15:20:33 -070082 private static final String TAG = "ChooseLockPattern";
83
Jim Miller17e9e192010-12-07 20:41:41 -080084 @Override
85 public Intent getIntent() {
86 Intent modIntent = new Intent(super.getIntent());
Maurice Lam6b19fa92014-11-25 19:25:56 -080087 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
Jim Miller17e9e192010-12-07 20:41:41 -080088 return modIntent;
89 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080090
Maurice Lam9990f392017-06-28 15:06:09 -070091 @Override
92 protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
93 resid = SetupWizardUtils.getTheme(getIntent());
94 super.onApplyThemeResource(theme, resid, first);
95 }
96
Maurice Lam2eb170c2017-04-28 16:18:47 -070097 public static class IntentBuilder {
98 private final Intent mIntent;
Jim Miller0698a212014-10-16 19:49:07 -070099
Maurice Lam2eb170c2017-04-28 16:18:47 -0700100 public IntentBuilder(Context context) {
101 mIntent = new Intent(context, ChooseLockPattern.class);
102 mIntent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false);
103 mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
Pavel Grafov40e187b2017-10-11 22:57:09 +0100104 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
Maurice Lam2eb170c2017-04-28 16:18:47 -0700105 }
Andres Moralesa0e12362015-04-02 09:00:41 -0700106
Maurice Lam2eb170c2017-04-28 16:18:47 -0700107 public IntentBuilder setUserId(int userId) {
108 mIntent.putExtra(Intent.EXTRA_USER_ID, userId);
109 return this;
110 }
111
112 public IntentBuilder setChallenge(long challenge) {
113 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
114 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
115 return this;
116 }
117
Rubin Xu010116a2019-09-11 17:36:37 +0100118 public IntentBuilder setPattern(LockscreenCredential pattern) {
Maurice Lam2eb170c2017-04-28 16:18:47 -0700119 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pattern);
120 return this;
121 }
122
Maurice Lamb49526e2017-05-31 17:55:43 -0700123 public IntentBuilder setForFingerprint(boolean forFingerprint) {
124 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
125 return this;
126 }
127
Kevin Chyn81dc0292018-06-28 14:59:38 -0700128 public IntentBuilder setForFace(boolean forFace) {
129 mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace);
130 return this;
131 }
132
Maurice Lam2eb170c2017-04-28 16:18:47 -0700133 public Intent build() {
134 return mIntent;
135 }
Andres Morales6609b0c2015-04-12 15:38:25 -0700136 }
137
Jim Miller00d24762009-12-22 19:04:57 -0800138 @Override
Amith Yamasania677ee22013-07-26 13:38:41 -0700139 protected boolean isValidFragment(String fragmentName) {
140 if (ChooseLockPatternFragment.class.getName().equals(fragmentName)) return true;
141 return false;
142 }
143
Maurice Lam6b19fa92014-11-25 19:25:56 -0800144 /* package */ Class<? extends Fragment> getFragmentClass() {
145 return ChooseLockPatternFragment.class;
146 }
147
Amith Yamasania677ee22013-07-26 13:38:41 -0700148 @Override
Udam Saini71fde522016-03-30 13:38:05 -0700149 protected void onCreate(Bundle savedInstanceState) {
Jim Miller17e9e192010-12-07 20:41:41 -0800150 // requestWindowFeature(Window.FEATURE_NO_TITLE);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800151 super.onCreate(savedInstanceState);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700152 final boolean forFingerprint = getIntent()
Maurice Lamb49526e2017-05-31 17:55:43 -0700153 .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700154 final boolean forFace = getIntent()
155 .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
156
157 int msg = R.string.lockpassword_choose_your_screen_lock_header;
158 if (forFingerprint) {
159 msg = R.string.lockpassword_choose_your_pattern_header_for_fingerprint;
160 } else if (forFace) {
161 msg = R.string.lockpassword_choose_your_pattern_header_for_face;
162 }
163
164 setTitle(msg);
Fan Zhang9db66a52019-05-10 14:18:33 -0700165 findViewById(R.id.content_parent).setFitsSystemWindows(false);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800166 }
167
168 @Override
169 public boolean onKeyDown(int keyCode, KeyEvent event) {
Jim Miller17e9e192010-12-07 20:41:41 -0800170 // *** TODO ***
171 // chooseLockPatternFragment.onKeyDown(keyCode, event);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800172 return super.onKeyDown(keyCode, event);
173 }
174
Doris Ling72489722017-11-16 11:03:40 -0800175 public static class ChooseLockPatternFragment extends InstrumentedFragment
pastychangc3c5a5c2019-01-17 15:44:08 +0800176 implements SaveAndFinishWorker.Listener {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800177
Jim Miller17e9e192010-12-07 20:41:41 -0800178 public static final int CONFIRM_EXISTING_REQUEST = 55;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800179
Jim Miller17e9e192010-12-07 20:41:41 -0800180 // how long after a confirmation message is shown before moving on
181 static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800182
Jim Miller17e9e192010-12-07 20:41:41 -0800183 // how long we wait to clear a wrong pattern
184 private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800185
pastychang7a083f82019-03-26 16:09:34 +0800186 protected static final int ID_EMPTY_MESSAGE = -1;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800187
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700188 private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
189
Rubin Xu010116a2019-09-11 17:36:37 +0100190 private LockscreenCredential mCurrentCredential;
Andres Morales6609b0c2015-04-12 15:38:25 -0700191 private boolean mHasChallenge;
192 private long mChallenge;
Jyun LuoLai11960ce2018-03-15 14:11:30 +0800193 protected TextView mTitleText;
Jim Miller17e9e192010-12-07 20:41:41 -0800194 protected TextView mHeaderText;
Maurice Lam7f5e1962017-09-08 17:51:58 -0700195 protected TextView mMessageText;
Jim Miller17e9e192010-12-07 20:41:41 -0800196 protected LockPatternView mLockPatternView;
197 protected TextView mFooterText;
pastychangc3c5a5c2019-01-17 15:44:08 +0800198 protected FooterButton mSkipOrClearButton;
199 private FooterButton mNextButton;
Rubin Xu010116a2019-09-11 17:36:37 +0100200 @VisibleForTesting protected LockscreenCredential mChosenPattern;
Jyun LuoLai11960ce2018-03-15 14:11:30 +0800201 private ColorStateList mDefaultHeaderColorList;
Jim Miller17e9e192010-12-07 20:41:41 -0800202
jackqdyulei011f0db2016-10-21 10:50:34 -0700203 // ScrollView that contains title and header, only exist in land mode
204 private ScrollView mTitleHeaderScrollView;
205
Jim Miller17e9e192010-12-07 20:41:41 -0800206 /**
207 * The patten used during the help screen to show how to draw a pattern.
208 */
209 private final List<LockPatternView.Cell> mAnimatePattern =
210 Collections.unmodifiableList(Lists.newArrayList(
211 LockPatternView.Cell.of(0, 0),
212 LockPatternView.Cell.of(0, 1),
213 LockPatternView.Cell.of(1, 1),
214 LockPatternView.Cell.of(2, 1)
215 ));
216
217 @Override
218 public void onActivityResult(int requestCode, int resultCode,
219 Intent data) {
220 super.onActivityResult(requestCode, resultCode, data);
221 switch (requestCode) {
222 case CONFIRM_EXISTING_REQUEST:
223 if (resultCode != Activity.RESULT_OK) {
224 getActivity().setResult(RESULT_FINISHED);
225 getActivity().finish();
Andres Moralesa0e12362015-04-02 09:00:41 -0700226 } else {
Rubin Xu010116a2019-09-11 17:36:37 +0100227 mCurrentCredential = data.getParcelableExtra(
Andres Moralesa0e12362015-04-02 09:00:41 -0700228 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
Jim Miller17e9e192010-12-07 20:41:41 -0800229 }
Andres Moralesa0e12362015-04-02 09:00:41 -0700230
Jim Miller17e9e192010-12-07 20:41:41 -0800231 updateStage(Stage.Introduction);
232 break;
233 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800234 }
235
Maurice Lamaf103b42014-12-03 15:17:46 -0800236 protected void setRightButtonEnabled(boolean enabled) {
pastychangc3c5a5c2019-01-17 15:44:08 +0800237 mNextButton.setEnabled(enabled);
Maurice Lamaf103b42014-12-03 15:17:46 -0800238 }
239
240 protected void setRightButtonText(int text) {
pastychangc3c5a5c2019-01-17 15:44:08 +0800241 mNextButton.setText(getActivity(), text);
Maurice Lamaf103b42014-12-03 15:17:46 -0800242 }
243
Jim Miller17e9e192010-12-07 20:41:41 -0800244 /**
245 * The pattern listener that responds according to a user choosing a new
246 * lock pattern.
247 */
248 protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
249 new LockPatternView.OnPatternListener() {
250
251 public void onPatternStart() {
252 mLockPatternView.removeCallbacks(mClearPatternRunnable);
253 patternInProgress();
254 }
255
256 public void onPatternCleared() {
257 mLockPatternView.removeCallbacks(mClearPatternRunnable);
258 }
259
260 public void onPatternDetected(List<LockPatternView.Cell> pattern) {
261 if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
262 if (mChosenPattern == null) throw new IllegalStateException(
263 "null chosen pattern in stage 'need to confirm");
Rubin Xu010116a2019-09-11 17:36:37 +0100264 try (LockscreenCredential confirmPattern =
265 LockscreenCredential.createPattern(pattern)) {
266 if (mChosenPattern.equals(confirmPattern)) {
267 updateStage(Stage.ChoiceConfirmed);
268 } else {
269 updateStage(Stage.ConfirmWrong);
270 }
Jim Miller17e9e192010-12-07 20:41:41 -0800271 }
272 } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
273 if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
274 updateStage(Stage.ChoiceTooShort);
275 } else {
Rubin Xu010116a2019-09-11 17:36:37 +0100276 mChosenPattern = LockscreenCredential.createPattern(pattern);
Jim Miller17e9e192010-12-07 20:41:41 -0800277 updateStage(Stage.FirstChoiceValid);
278 }
279 } else {
280 throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
281 + "entering the pattern.");
282 }
283 }
284
285 public void onPatternCellAdded(List<Cell> pattern) {
286
287 }
288
289 private void patternInProgress() {
290 mHeaderText.setText(R.string.lockpattern_recording_inprogress);
Jyun LuoLai11960ce2018-03-15 14:11:30 +0800291 if (mDefaultHeaderColorList != null) {
292 mHeaderText.setTextColor(mDefaultHeaderColorList);
293 }
Jim Miller17e9e192010-12-07 20:41:41 -0800294 mFooterText.setText("");
pastychangc3c5a5c2019-01-17 15:44:08 +0800295 mNextButton.setEnabled(false);
jackqdyulei011f0db2016-10-21 10:50:34 -0700296
297 if (mTitleHeaderScrollView != null) {
298 mTitleHeaderScrollView.post(new Runnable() {
299 @Override
300 public void run() {
301 mTitleHeaderScrollView.fullScroll(ScrollView.FOCUS_DOWN);
302 }
303 });
304 }
Jim Miller17e9e192010-12-07 20:41:41 -0800305 }
306 };
307
Chris Wren8a963ba2015-03-20 10:29:14 -0400308 @Override
Fan Zhang65076132016-08-08 10:25:13 -0700309 public int getMetricsCategory() {
Fan Zhang31b21002019-01-16 13:49:47 -0800310 return SettingsEnums.CHOOSE_LOCK_PATTERN;
Chris Wren8a963ba2015-03-20 10:29:14 -0400311 }
312
Jim Miller17e9e192010-12-07 20:41:41 -0800313
314 /**
315 * The states of the left footer button.
316 */
317 enum LeftButtonMode {
Jim Miller17e9e192010-12-07 20:41:41 -0800318 Retry(R.string.lockpattern_retry_button_text, true),
319 RetryDisabled(R.string.lockpattern_retry_button_text, false),
320 Gone(ID_EMPTY_MESSAGE, false);
321
322
323 /**
324 * @param text The displayed text for this mode.
325 * @param enabled Whether the button should be enabled.
326 */
327 LeftButtonMode(int text, boolean enabled) {
328 this.text = text;
329 this.enabled = enabled;
330 }
331
332 final int text;
333 final boolean enabled;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800334 }
335
Jim Miller17e9e192010-12-07 20:41:41 -0800336 /**
337 * The states of the right button.
338 */
339 enum RightButtonMode {
Maurice Lamc57b19d2017-06-23 19:15:06 -0700340 Continue(R.string.next_label, true),
341 ContinueDisabled(R.string.next_label, false),
Jim Miller17e9e192010-12-07 20:41:41 -0800342 Confirm(R.string.lockpattern_confirm_button_text, true),
343 ConfirmDisabled(R.string.lockpattern_confirm_button_text, false),
344 Ok(android.R.string.ok, true);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800345
Jim Miller17e9e192010-12-07 20:41:41 -0800346 /**
347 * @param text The displayed text for this mode.
348 * @param enabled Whether the button should be enabled.
349 */
350 RightButtonMode(int text, boolean enabled) {
351 this.text = text;
352 this.enabled = enabled;
353 }
354
355 final int text;
356 final boolean enabled;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800357 }
358
Jim Miller17e9e192010-12-07 20:41:41 -0800359 /**
360 * Keep track internally of where the user is in choosing a pattern.
361 */
362 protected enum Stage {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800363
Jim Miller17e9e192010-12-07 20:41:41 -0800364 Introduction(
Kevin Chyn81dc0292018-06-28 14:59:38 -0700365 R.string.lock_settings_picker_biometrics_added_security_message,
Maurice Lam7f5e1962017-09-08 17:51:58 -0700366 R.string.lockpassword_choose_your_pattern_message,
Jim Miller17e9e192010-12-07 20:41:41 -0800367 R.string.lockpattern_recording_intro_header,
Ajay Nadathura1314df2018-01-04 13:06:46 -0800368 LeftButtonMode.Gone, RightButtonMode.ContinueDisabled,
Jim Miller63cf89a2011-08-07 16:06:13 -0700369 ID_EMPTY_MESSAGE, true),
Jim Miller17e9e192010-12-07 20:41:41 -0800370 HelpScreen(
Maurice Lam7f5e1962017-09-08 17:51:58 -0700371 ID_EMPTY_MESSAGE, ID_EMPTY_MESSAGE, R.string.lockpattern_settings_help_how_to_record,
Jim Miller17e9e192010-12-07 20:41:41 -0800372 LeftButtonMode.Gone, RightButtonMode.Ok, ID_EMPTY_MESSAGE, false),
373 ChoiceTooShort(
Kevin Chyn81dc0292018-06-28 14:59:38 -0700374 R.string.lock_settings_picker_biometrics_added_security_message,
Maurice Lam7f5e1962017-09-08 17:51:58 -0700375 R.string.lockpassword_choose_your_pattern_message,
Jim Miller17e9e192010-12-07 20:41:41 -0800376 R.string.lockpattern_recording_incorrect_too_short,
377 LeftButtonMode.Retry, RightButtonMode.ContinueDisabled,
378 ID_EMPTY_MESSAGE, true),
379 FirstChoiceValid(
Kevin Chyn81dc0292018-06-28 14:59:38 -0700380 R.string.lock_settings_picker_biometrics_added_security_message,
Maurice Lam7f5e1962017-09-08 17:51:58 -0700381 R.string.lockpassword_choose_your_pattern_message,
Jim Miller17e9e192010-12-07 20:41:41 -0800382 R.string.lockpattern_pattern_entered_header,
383 LeftButtonMode.Retry, RightButtonMode.Continue, ID_EMPTY_MESSAGE, false),
384 NeedToConfirm(
Maurice Lam7f5e1962017-09-08 17:51:58 -0700385 ID_EMPTY_MESSAGE, ID_EMPTY_MESSAGE, R.string.lockpattern_need_to_confirm,
Ajay Nadathura1314df2018-01-04 13:06:46 -0800386 LeftButtonMode.Gone, RightButtonMode.ConfirmDisabled,
Jim Miller17e9e192010-12-07 20:41:41 -0800387 ID_EMPTY_MESSAGE, true),
388 ConfirmWrong(
Maurice Lam7f5e1962017-09-08 17:51:58 -0700389 ID_EMPTY_MESSAGE, ID_EMPTY_MESSAGE, R.string.lockpattern_need_to_unlock_wrong,
Ajay Nadathura1314df2018-01-04 13:06:46 -0800390 LeftButtonMode.Gone, RightButtonMode.ConfirmDisabled,
Jim Miller17e9e192010-12-07 20:41:41 -0800391 ID_EMPTY_MESSAGE, true),
392 ChoiceConfirmed(
Maurice Lam7f5e1962017-09-08 17:51:58 -0700393 ID_EMPTY_MESSAGE, ID_EMPTY_MESSAGE, R.string.lockpattern_pattern_confirmed_header,
Ajay Nadathura1314df2018-01-04 13:06:46 -0800394 LeftButtonMode.Gone, RightButtonMode.Confirm, ID_EMPTY_MESSAGE, false);
Jim Miller17e9e192010-12-07 20:41:41 -0800395
396
397 /**
Kevin Chyn81dc0292018-06-28 14:59:38 -0700398 * @param messageForBiometrics The message displayed at the top, above header for
Maurice Lam7f5e1962017-09-08 17:51:58 -0700399 * fingerprint flow.
400 * @param message The message displayed at the top.
Jim Miller17e9e192010-12-07 20:41:41 -0800401 * @param headerMessage The message displayed at the top.
402 * @param leftMode The mode of the left button.
403 * @param rightMode The mode of the right button.
404 * @param footerMessage The footer message.
405 * @param patternEnabled Whether the pattern widget is enabled.
406 */
Kevin Chyn81dc0292018-06-28 14:59:38 -0700407 Stage(int messageForBiometrics, int message, int headerMessage,
Jim Miller17e9e192010-12-07 20:41:41 -0800408 LeftButtonMode leftMode,
409 RightButtonMode rightMode,
410 int footerMessage, boolean patternEnabled) {
411 this.headerMessage = headerMessage;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700412 this.messageForBiometrics = messageForBiometrics;
Maurice Lam7f5e1962017-09-08 17:51:58 -0700413 this.message = message;
Jim Miller17e9e192010-12-07 20:41:41 -0800414 this.leftMode = leftMode;
415 this.rightMode = rightMode;
416 this.footerMessage = footerMessage;
417 this.patternEnabled = patternEnabled;
418 }
419
420 final int headerMessage;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700421 final int messageForBiometrics;
Maurice Lam7f5e1962017-09-08 17:51:58 -0700422 final int message;
Jim Miller17e9e192010-12-07 20:41:41 -0800423 final LeftButtonMode leftMode;
424 final RightButtonMode rightMode;
425 final int footerMessage;
426 final boolean patternEnabled;
427 }
428
429 private Stage mUiStage = Stage.Introduction;
430
431 private Runnable mClearPatternRunnable = new Runnable() {
432 public void run() {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800433 mLockPatternView.clearPattern();
Jim Miller17e9e192010-12-07 20:41:41 -0800434 }
435 };
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800436
Jim Miller17e9e192010-12-07 20:41:41 -0800437 private ChooseLockSettingsHelper mChooseLockSettingsHelper;
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700438 private SaveAndFinishWorker mSaveAndFinishWorker;
Ajay Nadathura1314df2018-01-04 13:06:46 -0800439 protected int mUserId;
Ajay Nadathur7b1d96a2018-01-11 13:25:26 -0800440 protected boolean mForFingerprint;
Kevin Chyn81dc0292018-06-28 14:59:38 -0700441 protected boolean mForFace;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800442
Jim Miller17e9e192010-12-07 20:41:41 -0800443 private static final String KEY_UI_STAGE = "uiStage";
444 private static final String KEY_PATTERN_CHOICE = "chosenPattern";
Andres Moralesa0e12362015-04-02 09:00:41 -0700445 private static final String KEY_CURRENT_PATTERN = "currentPattern";
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800446
Jim Miller17e9e192010-12-07 20:41:41 -0800447 @Override
448 public void onCreate(Bundle savedInstanceState) {
449 super.onCreate(savedInstanceState);
450 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
Amith Yamasani66026772013-09-25 14:05:33 -0700451 if (!(getActivity() instanceof ChooseLockPattern)) {
452 throw new SecurityException("Fragment contained in wrong activity");
453 }
Clara Bayarrife432e82015-10-12 12:07:02 +0100454 Intent intent = getActivity().getIntent();
455 // Only take this argument into account if it belongs to the current profile.
Benjamin Franz194300d2016-01-13 12:16:25 +0000456 mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras());
Adrian Roos62775bf2016-01-28 13:23:53 -0800457
458 if (intent.getBooleanExtra(
459 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
460 SaveAndFinishWorker w = new SaveAndFinishWorker();
461 final boolean required = getActivity().getIntent().getBooleanExtra(
462 EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
Rubin Xu010116a2019-09-11 17:36:37 +0100463 LockscreenCredential current = intent.getParcelableExtra(
Adrian Roos62775bf2016-01-28 13:23:53 -0800464 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
465 w.setBlocking(true);
466 w.setListener(this);
467 w.start(mChooseLockSettingsHelper.utils(), required,
Rubin Xu010116a2019-09-11 17:36:37 +0100468 false, 0, current, current, mUserId);
Adrian Roos62775bf2016-01-28 13:23:53 -0800469 }
Ajay Nadathur7af28ec2017-07-21 15:11:21 -0700470 mForFingerprint = intent.getBooleanExtra(
471 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
Kevin Chyn81dc0292018-06-28 14:59:38 -0700472 mForFace = intent.getBooleanExtra(
473 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
The Android Open Source Projecte6dd1fa2009-03-18 17:39:48 -0700474 }
Jim Miller00d24762009-12-22 19:04:57 -0800475
Jim Miller17e9e192010-12-07 20:41:41 -0800476 @Override
477 public View onCreateView(LayoutInflater inflater, ViewGroup container,
478 Bundle savedInstanceState) {
Maurice Lamd189ac52016-06-15 13:39:34 -0700479 final GlifLayout layout = (GlifLayout) inflater.inflate(
480 R.layout.choose_lock_pattern, container, false);
481 layout.setHeaderText(getActivity().getTitle());
Maurice Lam212dd952018-02-14 16:02:33 -0800482 if (getResources().getBoolean(R.bool.config_lock_pattern_minimal_ui)) {
Maurice Lam9c2fae82019-03-26 18:50:21 -0700483 View iconView = layout.findViewById(R.id.sud_layout_icon);
Maurice Lam212dd952018-02-14 16:02:33 -0800484 if (iconView != null) {
485 iconView.setVisibility(View.GONE);
486 }
487 } else {
488 if (mForFingerprint) {
489 layout.setIcon(getActivity().getDrawable(R.drawable.ic_fingerprint_header));
Kevin Chyn81dc0292018-06-28 14:59:38 -0700490 } else if (mForFace) {
491 layout.setIcon(getActivity().getDrawable(R.drawable.ic_face_header));
Maurice Lam212dd952018-02-14 16:02:33 -0800492 }
Ajay Nadathur7af28ec2017-07-21 15:11:21 -0700493 }
pastychangc3c5a5c2019-01-17 15:44:08 +0800494
pastychang9bdb59a2019-01-21 09:49:15 +0800495 final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
pastychangc3c5a5c2019-01-17 15:44:08 +0800496 mixin.setSecondaryButton(
497 new FooterButton.Builder(getActivity())
498 .setText(R.string.lockpattern_tutorial_cancel_label)
499 .setListener(this::onSkipOrClearButtonClick)
500 .setButtonType(FooterButton.ButtonType.OTHER)
501 .setTheme(R.style.SudGlifButton_Secondary)
502 .build()
503 );
504 mixin.setPrimaryButton(
505 new FooterButton.Builder(getActivity())
506 .setText(R.string.lockpattern_tutorial_continue_label)
507 .setListener(this::onNextButtonClick)
508 .setButtonType(FooterButton.ButtonType.NEXT)
509 .setTheme(R.style.SudGlifButton_Primary)
510 .build()
511 );
512 mSkipOrClearButton = mixin.getSecondaryButton();
513 mNextButton = mixin.getPrimaryButton();
514
Maurice Lamd189ac52016-06-15 13:39:34 -0700515 return layout;
Maurice Lam6b19fa92014-11-25 19:25:56 -0800516 }
Jim Miller17e9e192010-12-07 20:41:41 -0800517
Maurice Lam6b19fa92014-11-25 19:25:56 -0800518 @Override
519 public void onViewCreated(View view, Bundle savedInstanceState) {
520 super.onViewCreated(view, savedInstanceState);
pastychang79614822019-01-03 10:12:54 +0800521 mTitleText = view.findViewById(R.id.suc_layout_title);
Jim Miller17e9e192010-12-07 20:41:41 -0800522 mHeaderText = (TextView) view.findViewById(R.id.headerText);
Jyun LuoLai11960ce2018-03-15 14:11:30 +0800523 mDefaultHeaderColorList = mHeaderText.getTextColors();
pastychangfa68ec42019-04-12 16:22:17 +0800524 mMessageText = view.findViewById(R.id.sud_layout_description);
Jim Miller17e9e192010-12-07 20:41:41 -0800525 mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
526 mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
527 mLockPatternView.setTactileFeedbackEnabled(
528 mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
Vishwath Mohan670c2522018-02-16 12:22:57 -0800529 mLockPatternView.setFadePattern(false);
Jim Miller17e9e192010-12-07 20:41:41 -0800530
531 mFooterText = (TextView) view.findViewById(R.id.footerText);
532
jackqdyulei011f0db2016-10-21 10:50:34 -0700533 mTitleHeaderScrollView = (ScrollView) view.findViewById(R.id
534 .scroll_layout_title_header);
535
Jim Miller17e9e192010-12-07 20:41:41 -0800536 // make it so unhandled touch events within the unlock screen go to the
537 // lock pattern view.
538 final LinearLayoutWithDefaultTouchRecepient topLayout
539 = (LinearLayoutWithDefaultTouchRecepient) view.findViewById(
540 R.id.topLayout);
541 topLayout.setDefaultTouchRecepient(mLockPatternView);
542
543 final boolean confirmCredentials = getActivity().getIntent()
Maurice Lam2eb170c2017-04-28 16:18:47 -0700544 .getBooleanExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
Andres Morales6609b0c2015-04-12 15:38:25 -0700545 Intent intent = getActivity().getIntent();
Rubin Xu010116a2019-09-11 17:36:37 +0100546 mCurrentCredential =
547 intent.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
Andres Morales6609b0c2015-04-12 15:38:25 -0700548 mHasChallenge = intent.getBooleanExtra(
549 ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
550 mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
Jim Miller17e9e192010-12-07 20:41:41 -0800551
552 if (savedInstanceState == null) {
553 if (confirmCredentials) {
554 // first launch. As a security measure, we're in NeedToConfirm mode until we
555 // know there isn't an existing password or the user confirms their password.
556 updateStage(Stage.NeedToConfirm);
557 boolean launchedConfirmationActivity =
558 mChooseLockSettingsHelper.launchConfirmationActivity(
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700559 CONFIRM_EXISTING_REQUEST,
Clara Bayarrife432e82015-10-12 12:07:02 +0100560 getString(R.string.unlock_set_unlock_launch_picker_title), true,
561 mUserId);
Jim Miller17e9e192010-12-07 20:41:41 -0800562 if (!launchedConfirmationActivity) {
563 updateStage(Stage.Introduction);
564 }
565 } else {
566 updateStage(Stage.Introduction);
567 }
568 } else {
569 // restore from previous state
Rubin Xu010116a2019-09-11 17:36:37 +0100570 mChosenPattern = savedInstanceState.getParcelable(KEY_PATTERN_CHOICE);
Andres Moralesa0e12362015-04-02 09:00:41 -0700571
Rubin Xu010116a2019-09-11 17:36:37 +0100572 if (mCurrentCredential == null) {
573 mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_PATTERN);
Andres Moralesa0e12362015-04-02 09:00:41 -0700574 }
Jim Miller17e9e192010-12-07 20:41:41 -0800575 updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700576
577 // Re-attach to the exiting worker if there is one.
578 mSaveAndFinishWorker = (SaveAndFinishWorker) getFragmentManager().findFragmentByTag(
579 FRAGMENT_TAG_SAVE_AND_FINISH);
Jim Miller17e9e192010-12-07 20:41:41 -0800580 }
Jim Miller17e9e192010-12-07 20:41:41 -0800581 }
582
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700583 @Override
584 public void onResume() {
585 super.onResume();
Xiyuan Xiae47a2ab2015-09-01 11:29:36 -0700586 updateStage(mUiStage);
587
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700588 if (mSaveAndFinishWorker != null) {
589 setRightButtonEnabled(false);
590 mSaveAndFinishWorker.setListener(this);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700591 }
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700592 }
593
594 @Override
595 public void onPause() {
596 super.onPause();
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700597 if (mSaveAndFinishWorker != null) {
598 mSaveAndFinishWorker.setListener(null);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700599 }
600 }
601
Maurice Lamecd2b7b2014-12-01 10:41:49 -0800602 protected Intent getRedactionInterstitialIntent(Context context) {
Clara Bayarrif6077f42016-01-25 17:21:24 +0000603 return RedactionInterstitial.createStartIntent(context, mUserId);
Maurice Lamecd2b7b2014-12-01 10:41:49 -0800604 }
605
Maurice Lamaf103b42014-12-03 15:17:46 -0800606 public void handleLeftButton() {
607 if (mUiStage.leftMode == LeftButtonMode.Retry) {
Rubin Xu00089862019-11-14 10:51:29 +0000608 if (mChosenPattern != null) {
609 mChosenPattern.zeroize();
610 mChosenPattern = null;
611 }
Maurice Lamaf103b42014-12-03 15:17:46 -0800612 mLockPatternView.clearPattern();
613 updateStage(Stage.Introduction);
Maurice Lamaf103b42014-12-03 15:17:46 -0800614 } else {
615 throw new IllegalStateException("left footer button pressed, but stage of " +
616 mUiStage + " doesn't make sense");
617 }
618 }
619
620 public void handleRightButton() {
621 if (mUiStage.rightMode == RightButtonMode.Continue) {
622 if (mUiStage != Stage.FirstChoiceValid) {
623 throw new IllegalStateException("expected ui stage "
624 + Stage.FirstChoiceValid + " when button is "
625 + RightButtonMode.Continue);
626 }
627 updateStage(Stage.NeedToConfirm);
628 } else if (mUiStage.rightMode == RightButtonMode.Confirm) {
629 if (mUiStage != Stage.ChoiceConfirmed) {
630 throw new IllegalStateException("expected ui stage " + Stage.ChoiceConfirmed
631 + " when button is " + RightButtonMode.Confirm);
632 }
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700633 startSaveAndFinish();
Maurice Lamaf103b42014-12-03 15:17:46 -0800634 } else if (mUiStage.rightMode == RightButtonMode.Ok) {
635 if (mUiStage != Stage.HelpScreen) {
636 throw new IllegalStateException("Help screen is only mode with ok button, "
637 + "but stage is " + mUiStage);
638 }
639 mLockPatternView.clearPattern();
640 mLockPatternView.setDisplayMode(DisplayMode.Correct);
641 updateStage(Stage.Introduction);
642 }
643 }
644
pastychangc3c5a5c2019-01-17 15:44:08 +0800645 protected void onSkipOrClearButtonClick(View view) {
646 handleLeftButton();
647 }
648
649 protected void onNextButtonClick(View view) {
650 handleRightButton();
Jim Miller17e9e192010-12-07 20:41:41 -0800651 }
652
653 public boolean onKeyDown(int keyCode, KeyEvent event) {
654 if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
655 if (mUiStage == Stage.HelpScreen) {
656 updateStage(Stage.Introduction);
657 return true;
658 }
659 }
660 if (keyCode == KeyEvent.KEYCODE_MENU && mUiStage == Stage.Introduction) {
661 updateStage(Stage.HelpScreen);
662 return true;
663 }
664 return false;
665 }
666
667 public void onSaveInstanceState(Bundle outState) {
668 super.onSaveInstanceState(outState);
669
670 outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
671 if (mChosenPattern != null) {
Rubin Xu010116a2019-09-11 17:36:37 +0100672 outState.putParcelable(KEY_PATTERN_CHOICE, mChosenPattern);
Jim Miller17e9e192010-12-07 20:41:41 -0800673 }
Andres Moralesa0e12362015-04-02 09:00:41 -0700674
Rubin Xu010116a2019-09-11 17:36:37 +0100675 if (mCurrentCredential != null) {
676 outState.putParcelable(KEY_CURRENT_PATTERN, mCurrentCredential);
Andres Moralesa0e12362015-04-02 09:00:41 -0700677 }
Jim Miller17e9e192010-12-07 20:41:41 -0800678 }
679
680 /**
681 * Updates the messages and buttons appropriate to what stage the user
682 * is at in choosing a view. This doesn't handle clearing out the pattern;
683 * the pattern is expected to be in the right state.
684 * @param stage
685 */
686 protected void updateStage(Stage stage) {
alanveef72c32012-10-03 17:10:50 -0700687 final Stage previousStage = mUiStage;
Jim Miller17e9e192010-12-07 20:41:41 -0800688
689 mUiStage = stage;
690
691 // header text, footer text, visibility and
692 // enabled state all known from the stage
693 if (stage == Stage.ChoiceTooShort) {
694 mHeaderText.setText(
695 getResources().getString(
696 stage.headerMessage,
697 LockPatternUtils.MIN_LOCK_PATTERN_SIZE));
698 } else {
699 mHeaderText.setText(stage.headerMessage);
700 }
Kevin Chyn81dc0292018-06-28 14:59:38 -0700701 final boolean forBiometrics = mForFingerprint || mForFace;
702 int message = forBiometrics ? stage.messageForBiometrics : stage.message;
Maurice Lam7f5e1962017-09-08 17:51:58 -0700703 if (message == ID_EMPTY_MESSAGE) {
704 mMessageText.setText("");
705 } else {
706 mMessageText.setText(message);
707 }
Jim Miller17e9e192010-12-07 20:41:41 -0800708 if (stage.footerMessage == ID_EMPTY_MESSAGE) {
709 mFooterText.setText("");
710 } else {
711 mFooterText.setText(stage.footerMessage);
712 }
713
Jyun LuoLai11960ce2018-03-15 14:11:30 +0800714 if (stage == Stage.ConfirmWrong || stage == Stage.ChoiceTooShort) {
715 TypedValue typedValue = new TypedValue();
716 Theme theme = getActivity().getTheme();
717 theme.resolveAttribute(R.attr.colorError, typedValue, true);
718 mHeaderText.setTextColor(typedValue.data);
719
720 } else {
721 if (mDefaultHeaderColorList != null) {
722 mHeaderText.setTextColor(mDefaultHeaderColorList);
723 }
724
Kevin Chyn81dc0292018-06-28 14:59:38 -0700725 if (stage == Stage.NeedToConfirm && forBiometrics) {
Jyun LuoLai11960ce2018-03-15 14:11:30 +0800726 mHeaderText.setText("");
727 mTitleText.setText(R.string.lockpassword_draw_your_pattern_again_header);
728 }
729 }
730
pastychangc3c5a5c2019-01-17 15:44:08 +0800731 updateFooterLeftButton(stage);
Jim Miller17e9e192010-12-07 20:41:41 -0800732
Maurice Lamaf103b42014-12-03 15:17:46 -0800733 setRightButtonText(stage.rightMode.text);
734 setRightButtonEnabled(stage.rightMode.enabled);
Jim Miller17e9e192010-12-07 20:41:41 -0800735
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700736 // same for whether the pattern is enabled
Jim Miller17e9e192010-12-07 20:41:41 -0800737 if (stage.patternEnabled) {
738 mLockPatternView.enableInput();
739 } else {
740 mLockPatternView.disableInput();
741 }
742
743 // the rest of the stuff varies enough that it is easier just to handle
744 // on a case by case basis.
745 mLockPatternView.setDisplayMode(DisplayMode.Correct);
Selim Cinek00da4f62015-06-25 17:42:58 -0400746 boolean announceAlways = false;
Jim Miller17e9e192010-12-07 20:41:41 -0800747
748 switch (mUiStage) {
749 case Introduction:
750 mLockPatternView.clearPattern();
751 break;
752 case HelpScreen:
753 mLockPatternView.setPattern(DisplayMode.Animate, mAnimatePattern);
754 break;
755 case ChoiceTooShort:
756 mLockPatternView.setDisplayMode(DisplayMode.Wrong);
757 postClearPatternRunnable();
Selim Cinek00da4f62015-06-25 17:42:58 -0400758 announceAlways = true;
Jim Miller17e9e192010-12-07 20:41:41 -0800759 break;
760 case FirstChoiceValid:
761 break;
762 case NeedToConfirm:
763 mLockPatternView.clearPattern();
764 break;
765 case ConfirmWrong:
766 mLockPatternView.setDisplayMode(DisplayMode.Wrong);
767 postClearPatternRunnable();
Selim Cinek00da4f62015-06-25 17:42:58 -0400768 announceAlways = true;
Jim Miller17e9e192010-12-07 20:41:41 -0800769 break;
770 case ChoiceConfirmed:
771 break;
772 }
alanveef72c32012-10-03 17:10:50 -0700773
774 // If the stage changed, announce the header for accessibility. This
775 // is a no-op when accessibility is disabled.
Selim Cinek00da4f62015-06-25 17:42:58 -0400776 if (previousStage != stage || announceAlways) {
alanveef72c32012-10-03 17:10:50 -0700777 mHeaderText.announceForAccessibility(mHeaderText.getText());
778 }
Jim Miller17e9e192010-12-07 20:41:41 -0800779 }
780
pastychangc3c5a5c2019-01-17 15:44:08 +0800781 protected void updateFooterLeftButton(Stage stage) {
Ajay Nadathur7b1d96a2018-01-11 13:25:26 -0800782 if (stage.leftMode == LeftButtonMode.Gone) {
pastychangc3c5a5c2019-01-17 15:44:08 +0800783 mSkipOrClearButton.setVisibility(View.GONE);
Ajay Nadathur7b1d96a2018-01-11 13:25:26 -0800784 } else {
pastychangc3c5a5c2019-01-17 15:44:08 +0800785 mSkipOrClearButton.setVisibility(View.VISIBLE);
786 mSkipOrClearButton.setText(getActivity(), stage.leftMode.text);
787 mSkipOrClearButton.setEnabled(stage.leftMode.enabled);
Ajay Nadathur7b1d96a2018-01-11 13:25:26 -0800788 }
789 }
790
Jim Miller17e9e192010-12-07 20:41:41 -0800791 // clear the wrong pattern unless they have started a new one
792 // already
793 private void postClearPatternRunnable() {
794 mLockPatternView.removeCallbacks(mClearPatternRunnable);
795 mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
796 }
797
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700798 private void startSaveAndFinish() {
799 if (mSaveAndFinishWorker != null) {
800 Log.w(TAG, "startSaveAndFinish with an existing SaveAndFinishWorker.");
801 return;
802 }
Jim Miller17e9e192010-12-07 20:41:41 -0800803
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700804 setRightButtonEnabled(false);
Adrian Roos90d6c562014-11-24 17:17:13 +0100805
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700806 mSaveAndFinishWorker = new SaveAndFinishWorker();
Robin Lee5bb1e4f2016-01-27 17:21:00 +0000807 mSaveAndFinishWorker.setListener(this);
808
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700809 getFragmentManager().beginTransaction().add(mSaveAndFinishWorker,
810 FRAGMENT_TAG_SAVE_AND_FINISH).commit();
Robin Lee5bb1e4f2016-01-27 17:21:00 +0000811 getFragmentManager().executePendingTransactions();
Paul Lawrencecff37ec2015-08-03 09:44:23 -0700812
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700813 final boolean required = getActivity().getIntent().getBooleanExtra(
Jim Miller0698a212014-10-16 19:49:07 -0700814 EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700815 mSaveAndFinishWorker.start(mChooseLockSettingsHelper.utils(), required,
Rubin Xu010116a2019-09-11 17:36:37 +0100816 mHasChallenge, mChallenge, mChosenPattern, mCurrentCredential, mUserId);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700817 }
818
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700819 @Override
820 public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
821 getActivity().setResult(RESULT_FINISHED, resultData);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700822
Rubin Xu010116a2019-09-11 17:36:37 +0100823 if (mChosenPattern != null) {
824 mChosenPattern.zeroize();
825 }
826 if (mCurrentCredential != null) {
827 mCurrentCredential.zeroize();
Rich Canningsb27c4302019-02-19 13:15:30 -0800828 }
829
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700830 if (!wasSecureBefore) {
831 Intent intent = getRedactionInterstitialIntent(getActivity());
832 if (intent != null) {
833 startActivity(intent);
834 }
835 }
Udam Saini686ae492016-02-02 17:02:29 -0800836 getActivity().finish();
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700837 }
838 }
839
Clara Bayarri77c43452016-06-23 11:11:42 +0100840 public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700841
Rubin Xu010116a2019-09-11 17:36:37 +0100842 private LockscreenCredential mChosenPattern;
843 private LockscreenCredential mCurrentCredential;
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700844 private boolean mLockVirgin;
845
Rubin Xu010116a2019-09-11 17:36:37 +0100846 public void start(LockPatternUtils utils, boolean credentialRequired, boolean hasChallenge,
847 long challenge, LockscreenCredential chosenPattern,
848 LockscreenCredential currentCredential, int userId) {
Clara Bayarrib8a22e42015-12-18 16:40:18 +0000849 prepare(utils, credentialRequired, hasChallenge, challenge, userId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700850
Rubin Xu010116a2019-09-11 17:36:37 +0100851 mCurrentCredential = currentCredential != null ? currentCredential
852 : LockscreenCredential.createNone();
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700853 mChosenPattern = chosenPattern;
Clara Bayarrife432e82015-10-12 12:07:02 +0100854 mUserId = userId;
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700855
Clara Bayarrife432e82015-10-12 12:07:02 +0100856 mLockVirgin = !mUtils.isPatternEverChosen(mUserId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700857
858 start();
859 }
860
861 @Override
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +0000862 protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
Clara Bayarrife432e82015-10-12 12:07:02 +0100863 final int userId = mUserId;
Rubin Xu010116a2019-09-11 17:36:37 +0100864 final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential,
865 userId);
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +0000866 Intent result = null;
867 if (success && mHasChallenge) {
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700868 byte[] token;
869 try {
Rubin Xu010116a2019-09-11 17:36:37 +0100870 token = mUtils.verifyCredential(mChosenPattern, mChallenge, userId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700871 } catch (RequestThrottledException e) {
872 token = null;
873 }
874
875 if (token == null) {
876 Log.e(TAG, "critical: no token returned for known good pattern");
877 }
878
879 result = new Intent();
880 result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
881 }
Irina Dumitrescu4b96dc32019-02-28 15:35:36 +0000882 return Pair.create(success, result);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700883 }
884
885 @Override
886 protected void finish(Intent resultData) {
887 if (mLockVirgin) {
Clara Bayarrife432e82015-10-12 12:07:02 +0100888 mUtils.setVisiblePatternEnabled(true, mUserId);
Xiyuan Xia3e7e3d62015-08-25 15:04:57 -0700889 }
890
891 super.finish(resultData);
Jim Miller17e9e192010-12-07 20:41:41 -0800892 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800893 }
894}