blob: 34c15e64ff545c517142657bc179221b1b1ef159 [file] [log] [blame]
Jim Millerdcb3d842012-08-23 19:18:12 -07001/*
2 * Copyright (C) 2012 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 */
Jim Miller5ecd8112013-01-09 18:50:26 -080016package com.android.keyguard;
Jim Millerdcb3d842012-08-23 19:18:12 -070017
Jason Monkea03be12017-12-04 11:08:41 -050018import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
19import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
Jorim Jaggied3032b2016-10-07 16:49:34 +020020
Jim Millerdcb3d842012-08-23 19:18:12 -070021import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080022import android.content.res.ColorStateList;
Jim Miller57375342012-09-09 15:20:31 -070023import android.graphics.Rect;
Xiyuan Xia6e380582015-05-05 15:16:08 -070024import android.os.AsyncTask;
Jim Millerdcb3d842012-08-23 19:18:12 -070025import android.os.CountDownTimer;
26import android.os.SystemClock;
Selim Cinek30181972014-05-30 03:33:06 +020027import android.text.TextUtils;
Jim Millerdcb3d842012-08-23 19:18:12 -070028import android.util.AttributeSet;
29import android.util.Log;
30import android.view.MotionEvent;
31import android.view.View;
Selim Cinek30181972014-05-30 03:33:06 +020032import android.view.ViewGroup;
Jorim Jaggi98f85302014-08-07 17:45:04 +020033import android.view.animation.AnimationUtils;
Selim Cinek30181972014-05-30 03:33:06 +020034import android.view.animation.Interpolator;
Jim Miller3af630c2012-09-26 14:29:18 -070035import android.widget.LinearLayout;
Jim Millerdcb3d842012-08-23 19:18:12 -070036
Lucas Dupin2e838ac2019-04-17 16:50:58 -070037import com.android.internal.annotations.VisibleForTesting;
Jason Monkea03be12017-12-04 11:08:41 -050038import com.android.internal.util.LatencyTracker;
Xiyuan Xia6e380582015-05-05 15:16:08 -070039import com.android.internal.widget.LockPatternChecker;
Jim Millerdcb3d842012-08-23 19:18:12 -070040import com.android.internal.widget.LockPatternUtils;
41import com.android.internal.widget.LockPatternView;
Jorim Jaggi56733532015-06-09 15:25:40 -070042import com.android.settingslib.animation.AppearAnimationCreator;
43import com.android.settingslib.animation.AppearAnimationUtils;
44import com.android.settingslib.animation.DisappearAnimationUtils;
Sunny Goyal87fccf02019-08-13 17:39:10 -070045import com.android.systemui.R;
Jim Millerdcb3d842012-08-23 19:18:12 -070046
Jim Millerdcb3d842012-08-23 19:18:12 -070047import java.util.List;
48
Selim Cinek30181972014-05-30 03:33:06 +020049public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
Andrew Lee72b46d42015-01-30 13:23:21 -080050 AppearAnimationCreator<LockPatternView.CellState>,
51 EmergencyButton.EmergencyButtonCallback {
Jim Millerdcb3d842012-08-23 19:18:12 -070052
53 private static final String TAG = "SecurityPatternView";
Jorim Jaggi5cf17872014-03-26 18:31:48 +010054 private static final boolean DEBUG = KeyguardConstants.DEBUG;
Jim Millerdcb3d842012-08-23 19:18:12 -070055
56 // how long before we clear the wrong pattern
57 private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
58
59 // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK
60 private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
61
Jim Millerdcb3d842012-08-23 19:18:12 -070062 // how many cells the user has to cross before we poke the wakelock
63 private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
64
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070065 // How much we scale up the duration of the disappear animation when the current user is locked
66 public static final float DISAPPEAR_MULTIPLIER_LOCKED = 1.5f;
67
Lucas Dupinabb18f42019-05-20 19:10:22 -070068 // Extra padding, in pixels, that should eat touch events.
69 private static final int PATTERNS_TOUCH_AREA_EXTENSION = 40;
70
Adrian Roos7c11f8b2014-03-10 17:00:11 +010071 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Selim Cinek30181972014-05-30 03:33:06 +020072 private final AppearAnimationUtils mAppearAnimationUtils;
Selim Cinekf9c0e8f2014-11-11 13:41:02 +010073 private final DisappearAnimationUtils mDisappearAnimationUtils;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070074 private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
Lucas Dupin727890f2019-05-15 14:32:50 -070075 private final int[] mTmpPosition = new int[2];
76 private final Rect mTempRect = new Rect();
77 private final Rect mLockPatternScreenBounds = new Rect();
Adrian Roos7c11f8b2014-03-10 17:00:11 +010078
Jim Millerdcb3d842012-08-23 19:18:12 -070079 private CountDownTimer mCountdownTimer = null;
80 private LockPatternUtils mLockPatternUtils;
Xiyuan Xia6e380582015-05-05 15:16:08 -070081 private AsyncTask<?, ?, ?> mPendingLockCheck;
Jim Millerdcb3d842012-08-23 19:18:12 -070082 private LockPatternView mLockPatternView;
Jim Millerdcb3d842012-08-23 19:18:12 -070083 private KeyguardSecurityCallback mCallback;
Jim Millerdcb3d842012-08-23 19:18:12 -070084
85 /**
86 * Keeps track of the last time we poked the wake lock during dispatching of the touch event.
87 * Initialized to something guaranteed to make us poke the wakelock when the user starts
88 * drawing the pattern.
89 * @see #dispatchTouchEvent(android.view.MotionEvent)
90 */
91 private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
92
93 /**
94 * Useful for clearing out the wrong pattern after a delay
95 */
96 private Runnable mCancelPatternRunnable = new Runnable() {
Jim Miller51e3a672015-07-31 18:42:53 -070097 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -070098 public void run() {
99 mLockPatternView.clearPattern();
100 }
101 };
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700102 @VisibleForTesting
103 KeyguardMessageArea mSecurityMessageDisplay;
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500104 private View mEcaView;
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100105 private ViewGroup mContainer;
Jorim Jaggi76a16232014-08-08 17:00:47 +0200106 private int mDisappearYTranslation;
Jim Millerdcb3d842012-08-23 19:18:12 -0700107
108 enum FooterMode {
109 Normal,
110 ForgotLockPattern,
111 VerifyUnlocked
112 }
113
114 public KeyguardPatternView(Context context) {
115 this(context, null);
116 }
117
118 public KeyguardPatternView(Context context, AttributeSet attrs) {
119 super(context, attrs);
Adrian Roos7c11f8b2014-03-10 17:00:11 +0100120 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Jorim Jaggi98f85302014-08-07 17:45:04 +0200121 mAppearAnimationUtils = new AppearAnimationUtils(context,
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100122 AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* translationScale */,
123 2.0f /* delayScale */, AnimationUtils.loadInterpolator(
Jorim Jaggi98f85302014-08-07 17:45:04 +0200124 mContext, android.R.interpolator.linear_out_slow_in));
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100125 mDisappearAnimationUtils = new DisappearAnimationUtils(context,
126 125, 1.2f /* translationScale */,
Jorim Jaggi94f6f0612015-06-25 14:47:24 -0700127 0.6f /* delayScale */, AnimationUtils.loadInterpolator(
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100128 mContext, android.R.interpolator.fast_out_linear_in));
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700129 mDisappearAnimationUtilsLocked = new DisappearAnimationUtils(context,
130 (long) (125 * DISAPPEAR_MULTIPLIER_LOCKED), 1.2f /* translationScale */,
131 0.6f /* delayScale */, AnimationUtils.loadInterpolator(
132 mContext, android.R.interpolator.fast_out_linear_in));
Jorim Jaggi76a16232014-08-08 17:00:47 +0200133 mDisappearYTranslation = getResources().getDimensionPixelSize(
134 R.dimen.disappear_y_translation);
Jim Millerdcb3d842012-08-23 19:18:12 -0700135 }
136
Jim Miller51e3a672015-07-31 18:42:53 -0700137 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700138 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
139 mCallback = callback;
140 }
141
Jim Miller51e3a672015-07-31 18:42:53 -0700142 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700143 public void setLockPatternUtils(LockPatternUtils utils) {
144 mLockPatternUtils = utils;
145 }
146
147 @Override
148 protected void onFinishInflate() {
149 super.onFinishInflate();
Jim Millerdcb3d842012-08-23 19:18:12 -0700150 mLockPatternUtils = mLockPatternUtils == null
151 ? new LockPatternUtils(mContext) : mLockPatternUtils;
152
Alan Viverette51efddb2017-04-05 10:00:01 -0400153 mLockPatternView = findViewById(R.id.lockPatternView);
Jim Millerdcb3d842012-08-23 19:18:12 -0700154 mLockPatternView.setSaveEnabled(false);
Jim Millerdcb3d842012-08-23 19:18:12 -0700155 mLockPatternView.setOnPatternListener(new UnlockPatternListener());
Lucas Dupine1732742018-08-23 18:26:49 -0700156 mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
157 KeyguardUpdateMonitor.getCurrentUser()));
Jim Millerdcb3d842012-08-23 19:18:12 -0700158
Jim Millerdcb3d842012-08-23 19:18:12 -0700159 // vibrate mode will be the same for the life of this screen
160 mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
161
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500162 mEcaView = findViewById(R.id.keyguard_selector_fade_container);
Alan Viverette51efddb2017-04-05 10:00:01 -0400163 mContainer = findViewById(R.id.container);
Andrew Lee72b46d42015-01-30 13:23:21 -0800164
Alan Viverette51efddb2017-04-05 10:00:01 -0400165 EmergencyButton button = findViewById(R.id.emergency_call_button);
Andrew Leef98f7b92015-02-02 15:50:29 -0800166 if (button != null) {
167 button.setCallback(this);
168 }
Jian Jin44e4d822018-04-06 12:40:50 -0700169
170 View cancelBtn = findViewById(R.id.cancel_button);
171 if (cancelBtn != null) {
172 cancelBtn.setOnClickListener(view -> {
173 mCallback.reset();
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700174 mCallback.onCancelClicked();
Jian Jin44e4d822018-04-06 12:40:50 -0700175 });
176 }
Andrew Lee72b46d42015-01-30 13:23:21 -0800177 }
178
Jim Miller51e3a672015-07-31 18:42:53 -0700179 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700180 protected void onAttachedToWindow() {
181 super.onAttachedToWindow();
182 mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
183 }
184
185 @Override
Andrew Lee72b46d42015-01-30 13:23:21 -0800186 public void onEmergencyButtonClickedWhenInCall() {
187 mCallback.reset();
Jim Millerdcb3d842012-08-23 19:18:12 -0700188 }
189
Jim Millerdcb3d842012-08-23 19:18:12 -0700190 @Override
Jim Millerd2b82f72012-09-18 20:52:55 -0700191 public boolean onTouchEvent(MotionEvent ev) {
192 boolean result = super.onTouchEvent(ev);
Jim Millerdcb3d842012-08-23 19:18:12 -0700193 // as long as the user is entering a pattern (i.e sending a touch event that was handled
194 // by this screen), keep poking the wake lock so that the screen will stay on.
195 final long elapsed = SystemClock.elapsedRealtime() - mLastPokeTime;
196 if (result && (elapsed > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
197 mLastPokeTime = SystemClock.elapsedRealtime();
198 }
Jim Miller57375342012-09-09 15:20:31 -0700199 mTempRect.set(0, 0, 0, 0);
200 offsetRectIntoDescendantCoords(mLockPatternView, mTempRect);
201 ev.offsetLocation(mTempRect.left, mTempRect.top);
202 result = mLockPatternView.dispatchTouchEvent(ev) || result;
203 ev.offsetLocation(-mTempRect.left, -mTempRect.top);
Jim Millerdcb3d842012-08-23 19:18:12 -0700204 return result;
205 }
206
Jim Miller51e3a672015-07-31 18:42:53 -0700207 @Override
Lucas Dupin727890f2019-05-15 14:32:50 -0700208 protected void onLayout(boolean changed, int l, int t, int r, int b) {
209 super.onLayout(changed, l, t, r, b);
210 mLockPatternView.getLocationOnScreen(mTmpPosition);
Lucas Dupinabb18f42019-05-20 19:10:22 -0700211 mLockPatternScreenBounds.set(mTmpPosition[0] - PATTERNS_TOUCH_AREA_EXTENSION,
212 mTmpPosition[1] - PATTERNS_TOUCH_AREA_EXTENSION,
213 mTmpPosition[0] + mLockPatternView.getWidth() + PATTERNS_TOUCH_AREA_EXTENSION,
214 mTmpPosition[1] + mLockPatternView.getHeight() + PATTERNS_TOUCH_AREA_EXTENSION);
Lucas Dupin727890f2019-05-15 14:32:50 -0700215 }
216
217 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700218 public void reset() {
219 // reset lock pattern
Toni Barzic17fdb132015-10-16 13:38:11 -0700220 mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
221 KeyguardUpdateMonitor.getCurrentUser()));
Jim Millerdcb3d842012-08-23 19:18:12 -0700222 mLockPatternView.enableInput();
223 mLockPatternView.setEnabled(true);
224 mLockPatternView.clearPattern();
225
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700226 if (mSecurityMessageDisplay == null) {
227 return;
228 }
229
Jim Millerdcb3d842012-08-23 19:18:12 -0700230 // if the user is currently locked out, enforce it.
Adrian Roos8150d2a2015-04-16 17:11:20 -0700231 long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
Adrian Roosd6aa6cb2015-04-16 19:31:29 -0700232 KeyguardUpdateMonitor.getCurrentUser());
Jim Millerdcb3d842012-08-23 19:18:12 -0700233 if (deadline != 0) {
234 handleAttemptLockout(deadline);
235 } else {
Danielle Millett1625e872012-11-01 15:00:12 -0400236 displayDefaultSecurityMessage();
Jim Millerdcb3d842012-08-23 19:18:12 -0700237 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700238 }
239
Danielle Millett1625e872012-11-01 15:00:12 -0400240 private void displayDefaultSecurityMessage() {
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700241 if (mSecurityMessageDisplay != null) {
242 mSecurityMessageDisplay.setMessage("");
243 }
Danielle Millett1625e872012-11-01 15:00:12 -0400244 }
245
Adam Cohen6fb841f2012-10-24 13:15:38 -0700246 @Override
247 public void showUsabilityHint() {
248 }
249
Lucas Dupin7156bc72019-05-03 19:37:39 -0700250 @Override
251 public boolean disallowInterceptTouch(MotionEvent event) {
Lucas Dupinfc8de932019-06-13 14:20:52 -0700252 return !mLockPatternView.isEmpty()
253 || mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY());
Lucas Dupin7156bc72019-05-03 19:37:39 -0700254 }
255
Jim Millerdcb3d842012-08-23 19:18:12 -0700256 /** TODO: hook this up */
257 public void cleanUp() {
258 if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
259 mLockPatternUtils = null;
260 mLockPatternView.setOnPatternListener(null);
261 }
262
Jim Millerdcb3d842012-08-23 19:18:12 -0700263 private class UnlockPatternListener implements LockPatternView.OnPatternListener {
264
Jim Miller51e3a672015-07-31 18:42:53 -0700265 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700266 public void onPatternStart() {
267 mLockPatternView.removeCallbacks(mCancelPatternRunnable);
Adrian Roosdb327e92016-10-12 16:41:28 -0700268 mSecurityMessageDisplay.setMessage("");
Jim Millerdcb3d842012-08-23 19:18:12 -0700269 }
270
Jim Miller51e3a672015-07-31 18:42:53 -0700271 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700272 public void onPatternCleared() {
273 }
274
Jim Miller51e3a672015-07-31 18:42:53 -0700275 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700276 public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200277 mCallback.userActivity();
Lucas Dupinccf67212019-08-07 12:53:02 -0700278 mCallback.onUserInput();
Jim Millerdcb3d842012-08-23 19:18:12 -0700279 }
280
Jim Miller51e3a672015-07-31 18:42:53 -0700281 @Override
Xiyuan Xia6e380582015-05-05 15:16:08 -0700282 public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
283 mLockPatternView.disableInput();
284 if (mPendingLockCheck != null) {
285 mPendingLockCheck.cancel(false);
286 }
287
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800288 final int userId = KeyguardUpdateMonitor.getCurrentUser();
Andres Morales23974272015-05-14 22:42:26 -0700289 if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
290 mLockPatternView.enableInput();
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800291 onPatternChecked(userId, false, 0, false /* not valid - too short */);
Andres Morales23974272015-05-14 22:42:26 -0700292 return;
293 }
294
Jorim Jaggied3032b2016-10-07 16:49:34 +0200295 if (LatencyTracker.isEnabled(mContext)) {
296 LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
297 LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
298 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700299 mPendingLockCheck = LockPatternChecker.checkPattern(
300 mLockPatternUtils,
301 pattern,
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800302 userId,
Xiyuan Xia6e380582015-05-05 15:16:08 -0700303 new LockPatternChecker.OnCheckCallback() {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700304
305 @Override
306 public void onEarlyMatched() {
Jorim Jaggied3032b2016-10-07 16:49:34 +0200307 if (LatencyTracker.isEnabled(mContext)) {
308 LatencyTracker.getInstance(mContext).onActionEnd(
309 ACTION_CHECK_CREDENTIAL);
310 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700311 onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
312 true /* isValidPattern */);
313 }
314
Xiyuan Xia6e380582015-05-05 15:16:08 -0700315 @Override
Andres Morales23974272015-05-14 22:42:26 -0700316 public void onChecked(boolean matched, int timeoutMs) {
Jorim Jaggied3032b2016-10-07 16:49:34 +0200317 if (LatencyTracker.isEnabled(mContext)) {
318 LatencyTracker.getInstance(mContext).onActionEnd(
319 ACTION_CHECK_CREDENTIAL_UNLOCKED);
320 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700321 mLockPatternView.enableInput();
322 mPendingLockCheck = null;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700323 if (!matched) {
324 onPatternChecked(userId, false /* matched */, timeoutMs,
325 true /* isValidPattern */);
326 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700327 }
Jorim Jaggied3032b2016-10-07 16:49:34 +0200328
329 @Override
330 public void onCancelled() {
331 // We already got dismissed with the early matched callback, so we
332 // cancelled the check. However, we still need to note down the latency.
333 if (LatencyTracker.isEnabled(mContext)) {
334 LatencyTracker.getInstance(mContext).onActionEnd(
335 ACTION_CHECK_CREDENTIAL_UNLOCKED);
336 }
337 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700338 });
Jim Miller51e3a672015-07-31 18:42:53 -0700339 if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
340 mCallback.userActivity();
Lucas Dupinccf67212019-08-07 12:53:02 -0700341 mCallback.onUserInput();
Jim Miller51e3a672015-07-31 18:42:53 -0700342 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700343 }
344
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800345 private void onPatternChecked(int userId, boolean matched, int timeoutMs,
346 boolean isValidPattern) {
347 boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
Xiyuan Xia6e380582015-05-05 15:16:08 -0700348 if (matched) {
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800349 mCallback.reportUnlockAttempt(userId, true, 0);
350 if (dismissKeyguard) {
351 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700352 mCallback.dismiss(true, userId);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800353 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700354 } else {
Jim Millerdcb3d842012-08-23 19:18:12 -0700355 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
Jim Miller51e3a672015-07-31 18:42:53 -0700356 if (isValidPattern) {
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800357 mCallback.reportUnlockAttempt(userId, false, timeoutMs);
Jim Miller51e3a672015-07-31 18:42:53 -0700358 if (timeoutMs > 0) {
359 long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800360 userId, timeoutMs);
Jim Miller51e3a672015-07-31 18:42:53 -0700361 handleAttemptLockout(deadline);
362 }
363 }
364 if (timeoutMs == 0) {
Adrian Roosdb327e92016-10-12 16:41:28 -0700365 mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern);
Jim Millerdcb3d842012-08-23 19:18:12 -0700366 mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
367 }
368 }
369 }
370 }
371
Jim Millerdcb3d842012-08-23 19:18:12 -0700372 private void handleAttemptLockout(long elapsedRealtimeDeadline) {
373 mLockPatternView.clearPattern();
374 mLockPatternView.setEnabled(false);
375 final long elapsedRealtime = SystemClock.elapsedRealtime();
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200376 final long secondsInFuture = (long) Math.ceil(
377 (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
378 mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700379
380 @Override
381 public void onTick(long millisUntilFinished) {
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200382 final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
Kevin Chyne01c5e12017-08-29 19:04:25 -0700383 mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
384 R.plurals.kg_too_many_failed_attempts_countdown,
385 secondsRemaining, secondsRemaining));
Jim Millerdcb3d842012-08-23 19:18:12 -0700386 }
387
388 @Override
389 public void onFinish() {
390 mLockPatternView.setEnabled(true);
Danielle Millett1625e872012-11-01 15:00:12 -0400391 displayDefaultSecurityMessage();
Jim Millerdcb3d842012-08-23 19:18:12 -0700392 }
393
394 }.start();
395 }
396
397 @Override
398 public boolean needsInput() {
399 return false;
400 }
401
402 @Override
403 public void onPause() {
404 if (mCountdownTimer != null) {
405 mCountdownTimer.cancel();
406 mCountdownTimer = null;
407 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700408 if (mPendingLockCheck != null) {
409 mPendingLockCheck.cancel(false);
410 mPendingLockCheck = null;
411 }
Lucas Dupinc6b50c62018-10-09 20:00:35 -0700412 displayDefaultSecurityMessage();
Jim Millerdcb3d842012-08-23 19:18:12 -0700413 }
414
415 @Override
Chris Wrena042ac92012-11-07 11:37:06 -0500416 public void onResume(int reason) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700417 }
418
419 @Override
420 public KeyguardSecurityCallback getCallback() {
421 return mCallback;
422 }
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500423
424 @Override
Selim Cinek3122fa82015-06-18 01:38:59 -0700425 public void showPromptReason(int reason) {
426 switch (reason) {
427 case PROMPT_REASON_RESTART:
Adrian Roosdb327e92016-10-12 16:41:28 -0700428 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern);
Selim Cinek3122fa82015-06-18 01:38:59 -0700429 break;
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700430 case PROMPT_REASON_TIMEOUT:
Adrian Roosdb327e92016-10-12 16:41:28 -0700431 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700432 break;
Adrian Roosd6d253a2016-04-13 13:06:21 -0700433 case PROMPT_REASON_DEVICE_ADMIN:
Adrian Roosdb327e92016-10-12 16:41:28 -0700434 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin);
Adrian Roosd6d253a2016-04-13 13:06:21 -0700435 break;
436 case PROMPT_REASON_USER_REQUEST:
Adrian Roosdb327e92016-10-12 16:41:28 -0700437 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request);
Adrian Roosd6d253a2016-04-13 13:06:21 -0700438 break;
Adrian Roosc13723f2016-01-12 20:29:03 +0100439 case PROMPT_REASON_NONE:
440 break;
Selim Cinek3122fa82015-06-18 01:38:59 -0700441 default:
Adrian Roosdb327e92016-10-12 16:41:28 -0700442 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700443 break;
Selim Cinek3122fa82015-06-18 01:38:59 -0700444 }
445 }
446
447 @Override
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800448 public void showMessage(CharSequence message, ColorStateList colorState) {
Lucas Dupin51996bb2019-05-16 17:56:43 -0700449 if (colorState != null) {
450 mSecurityMessageDisplay.setNextMessageColor(colorState);
451 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700452 mSecurityMessageDisplay.setMessage(message);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700453 }
454
455 @Override
Jorim Jaggic14f8292014-05-27 02:25:45 +0200456 public void startAppearAnimation() {
Selim Cinek30181972014-05-30 03:33:06 +0200457 enableClipping(false);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200458 setAlpha(1f);
Jorim Jaggi76a16232014-08-08 17:00:47 +0200459 setTranslationY(mAppearAnimationUtils.getStartTranslation());
Jorim Jaggi613f55f2015-07-16 15:30:10 -0700460 AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
461 0, mAppearAnimationUtils.getInterpolator());
Jorim Jaggi56733532015-06-09 15:25:40 -0700462 mAppearAnimationUtils.startAnimation2d(
Selim Cinek30181972014-05-30 03:33:06 +0200463 mLockPatternView.getCellStates(),
464 new Runnable() {
465 @Override
466 public void run() {
467 enableClipping(true);
468 }
469 },
470 this);
Selim Cinek3122fa82015-06-18 01:38:59 -0700471 if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
472 mAppearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
Jorim Jaggi98f85302014-08-07 17:45:04 +0200473 AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
Selim Cinek30181972014-05-30 03:33:06 +0200474 mAppearAnimationUtils.getStartTranslation(),
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100475 true /* appearing */,
Selim Cinek30181972014-05-30 03:33:06 +0200476 mAppearAnimationUtils.getInterpolator(),
477 null /* finishRunnable */);
478 }
479 }
480
Jorim Jaggi76a16232014-08-08 17:00:47 +0200481 @Override
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100482 public boolean startDisappearAnimation(final Runnable finishRunnable) {
Jorim Jaggi031f7952016-09-01 16:39:26 -0700483 float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
484 ? DISAPPEAR_MULTIPLIER_LOCKED
485 : 1f;
Jorim Jaggi76a16232014-08-08 17:00:47 +0200486 mLockPatternView.clearPattern();
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100487 enableClipping(false);
488 setTranslationY(0);
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700489 AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */,
490 (long) (300 * durationMultiplier),
Jorim Jaggi613f55f2015-07-16 15:30:10 -0700491 -mDisappearAnimationUtils.getStartTranslation(),
492 mDisappearAnimationUtils.getInterpolator());
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700493
Jorim Jaggi031f7952016-09-01 16:39:26 -0700494 DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
495 .needsSlowUnlockTransition()
496 ? mDisappearAnimationUtilsLocked
497 : mDisappearAnimationUtils;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700498 disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
499 () -> {
500 enableClipping(true);
501 if (finishRunnable != null) {
502 finishRunnable.run();
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100503 }
504 }, KeyguardPatternView.this);
Selim Cinek3122fa82015-06-18 01:38:59 -0700505 if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
506 mDisappearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700507 (long) (200 * durationMultiplier),
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100508 - mDisappearAnimationUtils.getStartTranslation() * 3,
509 false /* appearing */,
510 mDisappearAnimationUtils.getInterpolator(),
511 null /* finishRunnable */);
512 }
Jorim Jaggi76a16232014-08-08 17:00:47 +0200513 return true;
514 }
515
Selim Cinek30181972014-05-30 03:33:06 +0200516 private void enableClipping(boolean enable) {
517 setClipChildren(enable);
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100518 mContainer.setClipToPadding(enable);
519 mContainer.setClipChildren(enable);
Selim Cinek30181972014-05-30 03:33:06 +0200520 }
521
522 @Override
523 public void createAnimation(final LockPatternView.CellState animatedCell, long delay,
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100524 long duration, float translationY, final boolean appearing,
525 Interpolator interpolator,
Selim Cinek30181972014-05-30 03:33:06 +0200526 final Runnable finishListener) {
Jorim Jaggi613f55f2015-07-16 15:30:10 -0700527 mLockPatternView.startCellStateAnimation(animatedCell,
528 1f, appearing ? 1f : 0f, /* alpha */
529 appearing ? translationY : 0f, appearing ? 0f : translationY, /* translation */
530 appearing ? 0f : 1f, 1f /* scale */,
531 delay, duration, interpolator, finishListener);
Selim Cinek30181972014-05-30 03:33:06 +0200532 if (finishListener != null) {
Selim Cinek30181972014-05-30 03:33:06 +0200533 // Also animate the Emergency call
Selim Cinekf9c0e8f2014-11-11 13:41:02 +0100534 mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, translationY,
535 appearing, interpolator, null);
Selim Cinek30181972014-05-30 03:33:06 +0200536 }
Jorim Jaggic14f8292014-05-27 02:25:45 +0200537 }
Jorim Jaggi76a16232014-08-08 17:00:47 +0200538
539 @Override
540 public boolean hasOverlappingRendering() {
541 return false;
542 }
Phil Weaver7d847b02018-02-13 16:02:35 -0800543
544 @Override
545 public CharSequence getTitle() {
546 return getContext().getString(
547 com.android.internal.R.string.keyguard_accessibility_pattern_unlock);
548 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700549}