blob: d52992fee86d50c73846ad144bb573687a7b16d7 [file] [log] [blame]
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001/*
2 * Copyright (C) 2008 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
Jason Monk39b46742015-09-10 15:52:51 -040019import android.app.Activity;
Fan Zhang31b21002019-01-16 13:49:47 -080020import android.app.settings.SettingsEnums;
Jason Monk39b46742015-09-10 15:52:51 -040021import android.content.Intent;
22import android.os.AsyncTask;
23import android.os.Bundle;
24import android.os.CountDownTimer;
25import android.os.SystemClock;
Clara Bayarri34ec5f92016-01-22 14:59:24 +000026import android.os.UserManager;
Jason Monk39b46742015-09-10 15:52:51 -040027import android.os.storage.StorageManager;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.ViewGroup;
31import android.view.animation.AnimationUtils;
32import android.view.animation.Interpolator;
33import android.widget.TextView;
34
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080035import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -070036import com.android.internal.widget.LockPatternChecker;
Jason Monk39b46742015-09-10 15:52:51 -040037import com.android.internal.widget.LockPatternUtils;
38import com.android.internal.widget.LockPatternView;
Jim Miller56544d02009-09-29 14:16:53 -070039import com.android.internal.widget.LockPatternView.Cell;
Rubin Xu010116a2019-09-11 17:36:37 +010040import com.android.internal.widget.LockscreenCredential;
Maurice Lam2eb170c2017-04-28 16:18:47 -070041import com.android.settings.R;
Jorim Jaggiff41a9a2015-06-09 15:31:28 -070042import com.android.settingslib.animation.AppearAnimationCreator;
43import com.android.settingslib.animation.AppearAnimationUtils;
44import com.android.settingslib.animation.DisappearAnimationUtils;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080045
Jorim Jaggiff41a9a2015-06-09 15:31:28 -070046import java.util.ArrayList;
Jorim Jaggiff41a9a2015-06-09 15:31:28 -070047import java.util.Collections;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080048import java.util.List;
49
50/**
51 * Launch this when you want the user to confirm their lock pattern.
52 *
53 * Sets an activity result of {@link Activity#RESULT_OK} when the user
54 * successfully confirmed their pattern.
55 */
Jorim Jaggi8a09b612015-04-06 17:47:18 -070056public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080057
Paul Lawrence20444042014-07-07 13:10:16 -070058 public static class InternalActivity extends ConfirmLockPattern {
59 }
60
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080061 private enum Stage {
62 NeedToUnlock,
63 NeedToUnlockWrong,
64 LockedOut
65 }
66
67 @Override
Jim Miller17e9e192010-12-07 20:41:41 -080068 public Intent getIntent() {
69 Intent modIntent = new Intent(super.getIntent());
70 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockPatternFragment.class.getName());
Jim Miller17e9e192010-12-07 20:41:41 -080071 return modIntent;
72 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080073
Amith Yamasania677ee22013-07-26 13:38:41 -070074 @Override
75 protected boolean isValidFragment(String fragmentName) {
76 if (ConfirmLockPatternFragment.class.getName().equals(fragmentName)) return true;
77 return false;
78 }
79
Jorim Jaggiff41a9a2015-06-09 15:31:28 -070080 public static class ConfirmLockPatternFragment extends ConfirmDeviceCredentialBaseFragment
Xiyuan Xia00b17fa2015-08-31 11:59:46 -070081 implements AppearAnimationCreator<Object>, CredentialCheckResultTracker.Listener {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080082
Xiyuan Xia00b17fa2015-08-31 11:59:46 -070083 private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080084
Jim Miller17e9e192010-12-07 20:41:41 -080085 private LockPatternView mLockPatternView;
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -070086 private AsyncTask<?, ?, ?> mPendingLockCheck;
Xiyuan Xia00b17fa2015-08-31 11:59:46 -070087 private CredentialCheckResultTracker mCredentialCheckResultTracker;
88 private boolean mDisappearing = false;
Jim Miller17e9e192010-12-07 20:41:41 -080089 private CountDownTimer mCountdownTimer;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080090
Jim Miller17e9e192010-12-07 20:41:41 -080091 private TextView mHeaderTextView;
Jorim Jaggi8a09b612015-04-06 17:47:18 -070092 private TextView mDetailsTextView;
Jim Miller17e9e192010-12-07 20:41:41 -080093
94 // caller-supplied text for various prompts
95 private CharSequence mHeaderText;
Jorim Jaggi8a09b612015-04-06 17:47:18 -070096 private CharSequence mDetailsText;
Jim Miller17e9e192010-12-07 20:41:41 -080097
Jorim Jaggiff41a9a2015-06-09 15:31:28 -070098 private AppearAnimationUtils mAppearAnimationUtils;
99 private DisappearAnimationUtils mDisappearAnimationUtils;
100
Alex Johnston7868acf2019-12-09 12:52:14 +0000101 private boolean mIsManagedProfile;
102
Jim Miller17e9e192010-12-07 20:41:41 -0800103 // required constructor for fragments
104 public ConfirmLockPatternFragment() {
105
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800106 }
107
Jim Miller17e9e192010-12-07 20:41:41 -0800108 @Override
Jim Miller17e9e192010-12-07 20:41:41 -0800109 public View onCreateView(LayoutInflater inflater, ViewGroup container,
110 Bundle savedInstanceState) {
Maurice Lamdaaf8f82017-03-10 15:31:30 -0800111 ConfirmLockPattern activity = (ConfirmLockPattern) getActivity();
112 View view = inflater.inflate(
Maurice Lam3e3b8a92018-03-21 18:21:04 -0700113 activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.NORMAL
114 ? R.layout.confirm_lock_pattern_normal
Maurice Lamdaaf8f82017-03-10 15:31:30 -0800115 : R.layout.confirm_lock_pattern,
116 container,
117 false);
Jim Miller17e9e192010-12-07 20:41:41 -0800118 mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
119 mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
pastychangfa68ec42019-04-12 16:22:17 +0800120 mDetailsTextView = (TextView) view.findViewById(R.id.sud_layout_description);
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700121 mErrorTextView = (TextView) view.findViewById(R.id.errorText);
Alex Johnston7868acf2019-12-09 12:52:14 +0000122
123 mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
Jim Miller17e9e192010-12-07 20:41:41 -0800124
125 // make it so unhandled touch events within the unlock screen go to the
126 // lock pattern view.
127 final LinearLayoutWithDefaultTouchRecepient topLayout
128 = (LinearLayoutWithDefaultTouchRecepient) view.findViewById(R.id.topLayout);
129 topLayout.setDefaultTouchRecepient(mLockPatternView);
130
131 Intent intent = getActivity().getIntent();
132 if (intent != null) {
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700133 mHeaderText = intent.getCharSequenceExtra(
134 ConfirmDeviceCredentialBaseFragment.HEADER_TEXT);
135 mDetailsText = intent.getCharSequenceExtra(
136 ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800137 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800138
Julia Reynolds36a38c92015-07-28 09:44:59 -0400139 mLockPatternView.setTactileFeedbackEnabled(
140 mLockPatternUtils.isTactileFeedbackEnabled());
141 mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
Andres Moralesb56324b2015-08-11 16:12:50 -0700142 mEffectiveUserId));
Jim Miller17e9e192010-12-07 20:41:41 -0800143 mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
Konstantin Lopyrev9aaf40d2010-05-13 16:33:13 -0700144 updateStage(Stage.NeedToUnlock);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800145
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700146 if (savedInstanceState == null) {
Jim Miller17e9e192010-12-07 20:41:41 -0800147 // on first launch, if no lock pattern is set, then finish with
148 // success (don't want user to get stuck confirming something that
149 // doesn't exist).
Adrian Roos5a9a3cd2017-03-30 18:02:25 -0700150 // Don't do this check for FRP though, because the pattern is not stored
151 // in a way that isLockPatternEnabled is aware of for that case.
152 // TODO(roosa): This block should no longer be needed since we removed the
153 // ability to disable the pattern in L. Remove this block after
154 // ensuring it's safe to do so. (Note that ConfirmLockPassword
155 // doesn't have this).
156 if (!mFrp && !mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) {
Jim Miller17e9e192010-12-07 20:41:41 -0800157 getActivity().setResult(Activity.RESULT_OK);
158 getActivity().finish();
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800159 }
160 }
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700161 mAppearAnimationUtils = new AppearAnimationUtils(getContext(),
162 AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 2f /* translationScale */,
163 1.3f /* delayScale */, AnimationUtils.loadInterpolator(
164 getContext(), android.R.interpolator.linear_out_slow_in));
165 mDisappearAnimationUtils = new DisappearAnimationUtils(getContext(),
166 125, 4f /* translationScale */,
167 0.3f /* delayScale */, AnimationUtils.loadInterpolator(
168 getContext(), android.R.interpolator.fast_out_linear_in),
169 new AppearAnimationUtils.RowTranslationScaler() {
170 @Override
171 public float getRowTranslationScale(int row, int numRows) {
172 return (float)(numRows - row) / numRows;
173 }
174 });
Julia Reynoldsce25af42015-07-08 16:56:31 -0400175 setAccessibilityTitle(mHeaderTextView.getText());
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700176
177 mCredentialCheckResultTracker = (CredentialCheckResultTracker) getFragmentManager()
178 .findFragmentByTag(FRAGMENT_TAG_CHECK_LOCK_RESULT);
179 if (mCredentialCheckResultTracker == null) {
180 mCredentialCheckResultTracker = new CredentialCheckResultTracker();
181 getFragmentManager().beginTransaction().add(mCredentialCheckResultTracker,
182 FRAGMENT_TAG_CHECK_LOCK_RESULT).commit();
183 }
Jim Miller17e9e192010-12-07 20:41:41 -0800184 return view;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800185 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800186
Jim Miller17e9e192010-12-07 20:41:41 -0800187 @Override
188 public void onSaveInstanceState(Bundle outState) {
189 // deliberately not calling super since we are managing this in full
Jim Miller17e9e192010-12-07 20:41:41 -0800190 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800191
Jim Miller17e9e192010-12-07 20:41:41 -0800192 @Override
193 public void onPause() {
194 super.onPause();
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800195
Jim Miller17e9e192010-12-07 20:41:41 -0800196 if (mCountdownTimer != null) {
197 mCountdownTimer.cancel();
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800198 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700199 mCredentialCheckResultTracker.setListener(null);
Jim Miller17e9e192010-12-07 20:41:41 -0800200 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800201
Jim Miller17e9e192010-12-07 20:41:41 -0800202 @Override
Fan Zhang65076132016-08-08 10:25:13 -0700203 public int getMetricsCategory() {
Fan Zhang31b21002019-01-16 13:49:47 -0800204 return SettingsEnums.CONFIRM_LOCK_PATTERN;
Chris Wren8a963ba2015-03-20 10:29:14 -0400205 }
206
207 @Override
Jim Miller17e9e192010-12-07 20:41:41 -0800208 public void onResume() {
209 super.onResume();
210
211 // if the user is currently locked out, enforce it.
Andres Morales7bdffd82015-08-04 16:55:00 -0700212 long deadline = mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId);
Jim Miller17e9e192010-12-07 20:41:41 -0800213 if (deadline != 0) {
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700214 mCredentialCheckResultTracker.clearResult();
Jim Miller17e9e192010-12-07 20:41:41 -0800215 handleAttemptLockout(deadline);
216 } else if (!mLockPatternView.isEnabled()) {
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700217 // The deadline has passed, but the timer was cancelled. Or the pending lock
218 // check was cancelled. Need to clean up.
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800219 updateStage(Stage.NeedToUnlock);
220 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700221 mCredentialCheckResultTracker.setListener(this);
Jim Miller17e9e192010-12-07 20:41:41 -0800222 }
223
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700224 @Override
Clara Bayarri9d357ea2016-01-28 17:50:53 +0000225 protected void onShowError() {
226 }
227
228 @Override
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700229 public void prepareEnterAnimation() {
230 super.prepareEnterAnimation();
231 mHeaderTextView.setAlpha(0f);
232 mCancelButton.setAlpha(0f);
233 mLockPatternView.setAlpha(0f);
234 mDetailsTextView.setAlpha(0f);
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700235 }
236
Tony Mak7655be02016-04-21 10:27:43 +0100237 private int getDefaultDetails() {
Adrian Roos6600dde2017-07-23 14:18:16 +0200238 if (mFrp) {
239 return R.string.lockpassword_confirm_your_pattern_details_frp;
240 }
Charles He4c96d9b2017-07-04 11:50:03 +0100241 final boolean isStrongAuthRequired = isStrongAuthRequired();
Alex Johnston28c6b572020-01-28 17:49:33 +0000242 if (mIsManagedProfile) {
Charles He4c96d9b2017-07-04 11:50:03 +0100243 return isStrongAuthRequired
244 ? R.string.lockpassword_strong_auth_required_work_pattern
245 : R.string.lockpassword_confirm_your_pattern_generic_profile;
Tony Mak7655be02016-04-21 10:27:43 +0100246 } else {
Charles He4c96d9b2017-07-04 11:50:03 +0100247 return isStrongAuthRequired
248 ? R.string.lockpassword_strong_auth_required_device_pattern
249 : R.string.lockpassword_confirm_your_pattern_generic;
Tony Mak7655be02016-04-21 10:27:43 +0100250 }
251 }
252
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700253 private Object[][] getActiveViews() {
254 ArrayList<ArrayList<Object>> result = new ArrayList<>();
255 result.add(new ArrayList<Object>(Collections.singletonList(mHeaderTextView)));
256 result.add(new ArrayList<Object>(Collections.singletonList(mDetailsTextView)));
257 if (mCancelButton.getVisibility() == View.VISIBLE) {
258 result.add(new ArrayList<Object>(Collections.singletonList(mCancelButton)));
259 }
260 LockPatternView.CellState[][] cellStates = mLockPatternView.getCellStates();
261 for (int i = 0; i < cellStates.length; i++) {
262 ArrayList<Object> row = new ArrayList<>();
263 for (int j = 0; j < cellStates[i].length; j++) {
264 row.add(cellStates[i][j]);
265 }
266 result.add(row);
267 }
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700268 Object[][] resultArr = new Object[result.size()][cellStates[0].length];
269 for (int i = 0; i < result.size(); i++) {
270 ArrayList<Object> row = result.get(i);
271 for (int j = 0; j < row.size(); j++) {
272 resultArr[i][j] = row.get(j);
273 }
274 }
275 return resultArr;
276 }
277
278 @Override
279 public void startEnterAnimation() {
280 super.startEnterAnimation();
281 mLockPatternView.setAlpha(1f);
282 mAppearAnimationUtils.startAnimation2d(getActiveViews(), null, this);
283 }
284
Jim Miller17e9e192010-12-07 20:41:41 -0800285 private void updateStage(Stage stage) {
Jim Miller17e9e192010-12-07 20:41:41 -0800286 switch (stage) {
287 case NeedToUnlock:
288 if (mHeaderText != null) {
289 mHeaderTextView.setText(mHeaderText);
290 } else {
Adrian Roos6600dde2017-07-23 14:18:16 +0200291 mHeaderTextView.setText(getDefaultHeader());
Jim Miller17e9e192010-12-07 20:41:41 -0800292 }
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700293 if (mDetailsText != null) {
294 mDetailsTextView.setText(mDetailsText);
Clara Bayarri34ec5f92016-01-22 14:59:24 +0000295 } else {
Tony Mak7655be02016-04-21 10:27:43 +0100296 mDetailsTextView.setText(getDefaultDetails());
Jim Miller17e9e192010-12-07 20:41:41 -0800297 }
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700298 mErrorTextView.setText("");
Charles He641c9fc2017-04-26 18:45:48 +0100299 updateErrorMessage(
300 mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
Jim Miller17e9e192010-12-07 20:41:41 -0800301
302 mLockPatternView.setEnabled(true);
303 mLockPatternView.enableInput();
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700304 mLockPatternView.clearPattern();
Jim Miller17e9e192010-12-07 20:41:41 -0800305 break;
306 case NeedToUnlockWrong:
Charles Hecaf95102017-08-18 17:35:27 +0100307 showError(R.string.lockpattern_need_to_unlock_wrong,
308 CLEAR_WRONG_ATTEMPT_TIMEOUT_MS);
Jim Miller17e9e192010-12-07 20:41:41 -0800309
310 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
311 mLockPatternView.setEnabled(true);
312 mLockPatternView.enableInput();
313 break;
314 case LockedOut:
315 mLockPatternView.clearPattern();
316 // enabled = false means: disable input, and have the
317 // appearance of being disabled.
318 mLockPatternView.setEnabled(false); // appearance of being disabled
319 break;
320 }
alanveef72c32012-10-03 17:10:50 -0700321
322 // Always announce the header for accessibility. This is a no-op
323 // when accessibility is disabled.
324 mHeaderTextView.announceForAccessibility(mHeaderTextView.getText());
Jim Miller17e9e192010-12-07 20:41:41 -0800325 }
326
Adrian Roos6600dde2017-07-23 14:18:16 +0200327 private int getDefaultHeader() {
Alex Johnston7868acf2019-12-09 12:52:14 +0000328 if (mFrp) return R.string.lockpassword_confirm_your_pattern_header_frp;
329 return mIsManagedProfile
330 ? R.string.lockpassword_confirm_your_work_pattern_header
Adrian Roos6600dde2017-07-23 14:18:16 +0200331 : R.string.lockpassword_confirm_your_pattern_header;
332 }
333
Jim Miller17e9e192010-12-07 20:41:41 -0800334 private Runnable mClearPatternRunnable = new Runnable() {
335 public void run() {
336 mLockPatternView.clearPattern();
337 }
338 };
339
340 // clear the wrong pattern unless they have started a new one
341 // already
342 private void postClearPatternRunnable() {
343 mLockPatternView.removeCallbacks(mClearPatternRunnable);
Charles Hecaf95102017-08-18 17:35:27 +0100344 mLockPatternView.postDelayed(mClearPatternRunnable, CLEAR_WRONG_ATTEMPT_TIMEOUT_MS);
Jim Miller17e9e192010-12-07 20:41:41 -0800345 }
346
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700347 @Override
Andres Morales59f59762015-04-16 16:30:31 -0700348 protected void authenticationSucceeded() {
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700349 mCredentialCheckResultTracker.setResult(true, new Intent(), 0, mEffectiveUserId);
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700350 }
351
352 private void startDisappearAnimation(final Intent intent) {
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700353 if (mDisappearing) {
354 return;
355 }
356 mDisappearing = true;
357
Maurice Lamdaaf8f82017-03-10 15:31:30 -0800358 final ConfirmLockPattern activity = (ConfirmLockPattern) getActivity();
359 // Bail if there is no active activity.
360 if (activity == null || activity.isFinishing()) {
361 return;
362 }
363 if (activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.DARK) {
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700364 mLockPatternView.clearPattern();
365 mDisappearAnimationUtils.startAnimation2d(getActiveViews(),
Maurice Lamdaaf8f82017-03-10 15:31:30 -0800366 () -> {
367 activity.setResult(RESULT_OK, intent);
368 activity.finish();
369 activity.overridePendingTransition(
370 R.anim.confirm_credential_close_enter,
371 R.anim.confirm_credential_close_exit);
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700372 }, this);
373 } else {
Maurice Lamdaaf8f82017-03-10 15:31:30 -0800374 activity.setResult(RESULT_OK, intent);
375 activity.finish();
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700376 }
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700377 }
378
Jim Miller17e9e192010-12-07 20:41:41 -0800379 /**
380 * The pattern listener that responds according to a user confirming
381 * an existing lock pattern.
382 */
383 private LockPatternView.OnPatternListener mConfirmExistingLockPatternListener
384 = new LockPatternView.OnPatternListener() {
385
386 public void onPatternStart() {
387 mLockPatternView.removeCallbacks(mClearPatternRunnable);
388 }
389
390 public void onPatternCleared() {
391 mLockPatternView.removeCallbacks(mClearPatternRunnable);
392 }
393
394 public void onPatternCellAdded(List<Cell> pattern) {
395
396 }
397
398 public void onPatternDetected(List<LockPatternView.Cell> pattern) {
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700399 if (mPendingLockCheck != null || mDisappearing) {
400 return;
Andres Morales6609b0c2015-04-12 15:38:25 -0700401 }
402
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700403 mLockPatternView.setEnabled(false);
404
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700405 final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
406 ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
Rubin Xu010116a2019-09-11 17:36:37 +0100407 final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
408 //TODO: how to sanitize this?
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700409 Intent intent = new Intent();
410 if (verifyChallenge) {
411 if (isInternalActivity()) {
Rubin Xu010116a2019-09-11 17:36:37 +0100412 startVerifyPattern(credential, intent);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700413 return;
414 }
415 } else {
Rubin Xu010116a2019-09-11 17:36:37 +0100416 startCheckPattern(credential, intent);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700417 return;
418 }
419
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700420 mCredentialCheckResultTracker.setResult(false, intent, 0, mEffectiveUserId);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700421 }
422
423 private boolean isInternalActivity() {
424 return getActivity() instanceof ConfirmLockPattern.InternalActivity;
425 }
426
Rubin Xu010116a2019-09-11 17:36:37 +0100427 private void startVerifyPattern(final LockscreenCredential pattern,
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700428 final Intent intent) {
Andres Morales7bdffd82015-08-04 16:55:00 -0700429 final int localEffectiveUserId = mEffectiveUserId;
Ricky Wai996d0df2016-04-05 16:33:47 +0100430 final int localUserId = mUserId;
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700431 long challenge = getActivity().getIntent().getLongExtra(
432 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
Ricky Wai996d0df2016-04-05 16:33:47 +0100433 final LockPatternChecker.OnVerifyCallback onVerifyCallback =
434 new LockPatternChecker.OnVerifyCallback() {
435 @Override
436 public void onVerified(byte[] token, int timeoutMs) {
437 mPendingLockCheck = null;
438 boolean matched = false;
439 if (token != null) {
440 matched = true;
Victor Chang5e0a46b2016-05-13 17:06:59 +0100441 if (mReturnCredentials) {
442 intent.putExtra(
443 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
444 token);
445 }
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700446 }
Ricky Wai996d0df2016-04-05 16:33:47 +0100447 mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
448 localEffectiveUserId);
449 }
450 };
451 mPendingLockCheck = (localEffectiveUserId == localUserId)
Rubin Xu010116a2019-09-11 17:36:37 +0100452 ? LockPatternChecker.verifyCredential(
Ricky Wai996d0df2016-04-05 16:33:47 +0100453 mLockPatternUtils, pattern, challenge, localUserId,
454 onVerifyCallback)
455 : LockPatternChecker.verifyTiedProfileChallenge(
Rubin Xu010116a2019-09-11 17:36:37 +0100456 mLockPatternUtils, pattern,
457 challenge, localUserId, onVerifyCallback);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700458 }
459
Rubin Xu010116a2019-09-11 17:36:37 +0100460 private void startCheckPattern(final LockscreenCredential pattern,
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700461 final Intent intent) {
Andres Morales864d13e2015-05-27 13:04:38 -0700462 if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
Tony Mak818312d2016-07-20 09:55:25 +0100463 // Pattern size is less than the minimum, do not count it as an fail attempt.
464 onPatternChecked(false, intent, 0, mEffectiveUserId, false /* newResult */);
Andres Morales91e6c492015-05-15 15:20:33 -0700465 return;
466 }
467
Andres Morales7bdffd82015-08-04 16:55:00 -0700468 final int localEffectiveUserId = mEffectiveUserId;
Rubin Xu010116a2019-09-11 17:36:37 +0100469 mPendingLockCheck = LockPatternChecker.checkCredential(
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700470 mLockPatternUtils,
471 pattern,
Andres Morales7bdffd82015-08-04 16:55:00 -0700472 localEffectiveUserId,
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700473 new LockPatternChecker.OnCheckCallback() {
474 @Override
Andres Morales91e6c492015-05-15 15:20:33 -0700475 public void onChecked(boolean matched, int timeoutMs) {
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700476 mPendingLockCheck = null;
Victor Chang5e0a46b2016-05-13 17:06:59 +0100477 if (matched && isInternalActivity() && mReturnCredentials) {
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700478 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
479 StorageManager.CRYPT_TYPE_PATTERN);
480 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
Rubin Xu010116a2019-09-11 17:36:37 +0100481 pattern);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700482 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700483 mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
Andres Morales7bdffd82015-08-04 16:55:00 -0700484 localEffectiveUserId);
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700485 }
486 });
487 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700488 };
Xiyuan Xiabf9ac6b2015-05-05 16:04:00 -0700489
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700490 private void onPatternChecked(boolean matched, Intent intent, int timeoutMs,
Clara Bayarri9d357ea2016-01-28 17:50:53 +0000491 int effectiveUserId, boolean newResult) {
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700492 mLockPatternView.setEnabled(true);
493 if (matched) {
Clara Bayarri9d357ea2016-01-28 17:50:53 +0000494 if (newResult) {
Kevin Chyn127da9c2018-11-09 16:13:53 -0800495 ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
496 mUserManager, mEffectiveUserId);
Clara Bayarri9d357ea2016-01-28 17:50:53 +0000497 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700498 startDisappearAnimation(intent);
Kevin Chyn127da9c2018-11-09 16:13:53 -0800499 ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700500 } else {
501 if (timeoutMs > 0) {
Ricky Wai9aa434c2016-06-27 11:10:09 +0100502 refreshLockScreen();
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700503 long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
504 effectiveUserId, timeoutMs);
505 handleAttemptLockout(deadline);
Jim Miller17e9e192010-12-07 20:41:41 -0800506 } else {
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700507 updateStage(Stage.NeedToUnlockWrong);
508 postClearPatternRunnable();
Jim Miller17e9e192010-12-07 20:41:41 -0800509 }
Clara Bayarri9d357ea2016-01-28 17:50:53 +0000510 if (newResult) {
511 reportFailedAttempt();
512 }
Jim Miller17e9e192010-12-07 20:41:41 -0800513 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700514 }
515
516 @Override
517 public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs,
Clara Bayarri9d357ea2016-01-28 17:50:53 +0000518 int effectiveUserId, boolean newResult) {
519 onPatternChecked(matched, intent, timeoutMs, effectiveUserId, newResult);
520 }
521
522 @Override
Charles He641c9fc2017-04-26 18:45:48 +0100523 protected int getLastTryErrorMessage(int userType) {
524 switch (userType) {
525 case USER_TYPE_PRIMARY:
526 return R.string.lock_last_pattern_attempt_before_wipe_device;
527 case USER_TYPE_MANAGED_PROFILE:
528 return R.string.lock_last_pattern_attempt_before_wipe_profile;
529 case USER_TYPE_SECONDARY:
530 return R.string.lock_last_pattern_attempt_before_wipe_user;
531 default:
532 throw new IllegalArgumentException("Unrecognized user type:" + userType);
533 }
Xiyuan Xia00b17fa2015-08-31 11:59:46 -0700534 }
Jim Miller17e9e192010-12-07 20:41:41 -0800535
Jim Miller17e9e192010-12-07 20:41:41 -0800536 private void handleAttemptLockout(long elapsedRealtimeDeadline) {
537 updateStage(Stage.LockedOut);
538 long elapsedRealtime = SystemClock.elapsedRealtime();
539 mCountdownTimer = new CountDownTimer(
540 elapsedRealtimeDeadline - elapsedRealtime,
541 LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
542
543 @Override
544 public void onTick(long millisUntilFinished) {
Jim Miller17e9e192010-12-07 20:41:41 -0800545 final int secondsCountdown = (int) (millisUntilFinished / 1000);
Xiyuan Xia4458fd62015-06-02 15:21:51 -0700546 mErrorTextView.setText(getString(
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700547 R.string.lockpattern_too_many_failed_confirmation_attempts,
Jim Miller17e9e192010-12-07 20:41:41 -0800548 secondsCountdown));
549 }
550
551 @Override
552 public void onFinish() {
Jim Miller17e9e192010-12-07 20:41:41 -0800553 updateStage(Stage.NeedToUnlock);
554 }
555 }.start();
556 }
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700557
558 @Override
559 public void createAnimation(Object obj, long delay,
560 long duration, float translationY, final boolean appearing,
561 Interpolator interpolator,
562 final Runnable finishListener) {
563 if (obj instanceof LockPatternView.CellState) {
564 final LockPatternView.CellState animatedCell = (LockPatternView.CellState) obj;
Jorim Jaggif5b17e52015-07-21 15:34:26 -0700565 mLockPatternView.startCellStateAnimation(animatedCell,
566 1f, appearing ? 1f : 0f, /* alpha */
567 appearing ? translationY : 0f, /* startTranslation */
568 appearing ? 0f : translationY, /* endTranslation */
569 appearing ? 0f : 1f, 1f /* scale */,
570 delay, duration, interpolator, finishListener);
Jorim Jaggiff41a9a2015-06-09 15:31:28 -0700571 } else {
572 mAppearAnimationUtils.createAnimation((View) obj, delay, duration, translationY,
573 appearing, interpolator, finishListener);
574 }
575 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800576 }
577}