blob: d45603fd23ff2f221e3d53e3feb5447a42217749 [file] [log] [blame]
Daniel Sandler69bdee72012-10-23 16:45:50 -04001/*
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 */
16
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
Daniel Sandler69bdee72012-10-23 16:45:50 -040018
Jason Monkea03be12017-12-04 11:08:41 -050019import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
20import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
Jorim Jaggid0565172016-09-15 16:31:14 -070021
Daniel Sandler69bdee72012-10-23 16:45:50 -040022import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080023import android.content.res.ColorStateList;
Xiyuan Xia6e380582015-05-05 15:16:08 -070024import android.os.AsyncTask;
Daniel Sandler69bdee72012-10-23 16:45:50 -040025import android.os.CountDownTimer;
26import android.os.SystemClock;
Michael Jurka1254f2f2012-10-25 11:44:31 -070027import android.util.AttributeSet;
28import android.view.HapticFeedbackConstants;
Daniel Sandler69bdee72012-10-23 16:45:50 -040029import android.view.KeyEvent;
Michael Jurka1254f2f2012-10-25 11:44:31 -070030import android.view.View;
Daniel Sandler69bdee72012-10-23 16:45:50 -040031import android.widget.LinearLayout;
Daniel Sandler69bdee72012-10-23 16:45:50 -040032
Jason Monkea03be12017-12-04 11:08:41 -050033import com.android.internal.util.LatencyTracker;
Xiyuan Xia6e380582015-05-05 15:16:08 -070034import com.android.internal.widget.LockPatternChecker;
Michael Jurka1254f2f2012-10-25 11:44:31 -070035import com.android.internal.widget.LockPatternUtils;
Sunny Goyal87fccf02019-08-13 17:39:10 -070036import com.android.systemui.R;
Daniel Sandler69bdee72012-10-23 16:45:50 -040037
Rich Canningsf64ec632019-02-21 12:40:36 -080038import java.util.Arrays;
39
Daniel Sandler69bdee72012-10-23 16:45:50 -040040/**
41 * Base class for PIN and password unlock screens.
42 */
43public abstract class KeyguardAbsKeyInputView extends LinearLayout
Andrew Lee72b46d42015-01-30 13:23:21 -080044 implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
Daniel Sandler69bdee72012-10-23 16:45:50 -040045 protected KeyguardSecurityCallback mCallback;
Daniel Sandler69bdee72012-10-23 16:45:50 -040046 protected LockPatternUtils mLockPatternUtils;
Xiyuan Xia6e380582015-05-05 15:16:08 -070047 protected AsyncTask<?, ?, ?> mPendingLockCheck;
Daniel Sandler69bdee72012-10-23 16:45:50 -040048 protected SecurityMessageDisplay mSecurityMessageDisplay;
Chris Wrenc0ae9e62012-11-05 13:16:31 -050049 protected View mEcaView;
Daniel Sandleracb60fb2012-10-25 10:46:37 -040050 protected boolean mEnableHaptics;
Jim Millered7dcc22015-08-25 19:36:22 -070051 private boolean mDismissing;
lumarkd62bfd22019-01-10 15:29:11 +080052 protected boolean mResumed;
Hidenari Koshimae5be868c2014-08-21 11:27:33 +020053 private CountDownTimer mCountdownTimer = null;
Daniel Sandler69bdee72012-10-23 16:45:50 -040054
55 // To avoid accidental lockout due to events while the device in in the pocket, ignore
56 // any passwords with length less than or equal to this length.
57 protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
58
Daniel Sandler69bdee72012-10-23 16:45:50 -040059 public KeyguardAbsKeyInputView(Context context) {
60 this(context, null);
61 }
62
63 public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
64 super(context, attrs);
65 }
66
Jim Miller51e3a672015-07-31 18:42:53 -070067 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -040068 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
69 mCallback = callback;
70 }
71
Jim Miller51e3a672015-07-31 18:42:53 -070072 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -040073 public void setLockPatternUtils(LockPatternUtils utils) {
74 mLockPatternUtils = utils;
Daniel Sandleracb60fb2012-10-25 10:46:37 -040075 mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
Daniel Sandler69bdee72012-10-23 16:45:50 -040076 }
77
Jim Miller51e3a672015-07-31 18:42:53 -070078 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -040079 public void reset() {
80 // start fresh
Jim Millered7dcc22015-08-25 19:36:22 -070081 mDismissing = false;
Jim Miller4db942c2016-05-16 18:06:50 -070082 resetPasswordText(false /* animate */, false /* announce */);
Daniel Sandler69bdee72012-10-23 16:45:50 -040083 // if the user is currently locked out, enforce it.
Adrian Roos8150d2a2015-04-16 17:11:20 -070084 long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070085 KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7d5e00a2013-10-11 22:45:57 -070086 if (shouldLockout(deadline)) {
Daniel Sandler69bdee72012-10-23 16:45:50 -040087 handleAttemptLockout(deadline);
88 } else {
89 resetState();
90 }
91 }
92
Jim Miller7d5e00a2013-10-11 22:45:57 -070093 // Allow subclasses to override this behavior
94 protected boolean shouldLockout(long deadline) {
95 return deadline != 0;
96 }
97
Daniel Sandler8a26bf52012-10-30 13:29:50 -040098 protected abstract int getPasswordTextViewId();
Daniel Sandler69bdee72012-10-23 16:45:50 -040099 protected abstract void resetState();
100
101 @Override
102 protected void onFinishInflate() {
Daniel Sandleracb60fb2012-10-25 10:46:37 -0400103 mLockPatternUtils = new LockPatternUtils(mContext);
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500104 mEcaView = findViewById(R.id.keyguard_selector_fade_container);
Andrew Lee72b46d42015-01-30 13:23:21 -0800105
Alan Viverette51efddb2017-04-05 10:00:01 -0400106 EmergencyButton button = findViewById(R.id.emergency_call_button);
Andrew Leef98f7b92015-02-02 15:50:29 -0800107 if (button != null) {
108 button.setCallback(this);
109 }
Andrew Lee72b46d42015-01-30 13:23:21 -0800110 }
111
Jim Miller51e3a672015-07-31 18:42:53 -0700112 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700113 protected void onAttachedToWindow() {
114 super.onAttachedToWindow();
115 mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
116 }
117
118 @Override
Andrew Lee72b46d42015-01-30 13:23:21 -0800119 public void onEmergencyButtonClickedWhenInCall() {
120 mCallback.reset();
Daniel Sandler69bdee72012-10-23 16:45:50 -0400121 }
122
Daniel Sandler261b18a2012-11-01 23:54:03 -0400123 /*
124 * Override this if you have a different string for "wrong password"
125 *
126 * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
127 */
128 protected int getWrongPasswordStringId() {
129 return R.string.kg_wrong_password;
130 }
131
Daniel Sandler69bdee72012-10-23 16:45:50 -0400132 protected void verifyPasswordAndUnlock() {
Jim Millered7dcc22015-08-25 19:36:22 -0700133 if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
134
Rich Canningsf64ec632019-02-21 12:40:36 -0800135 final byte[] entry = getPasswordText();
Xiyuan Xiade26ea62015-05-19 15:00:41 -0700136 setPasswordEntryInputEnabled(false);
Xiyuan Xia6e380582015-05-05 15:16:08 -0700137 if (mPendingLockCheck != null) {
138 mPendingLockCheck.cancel(false);
139 }
Andres Morales23974272015-05-14 22:42:26 -0700140
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800141 final int userId = KeyguardUpdateMonitor.getCurrentUser();
Rich Canningsf64ec632019-02-21 12:40:36 -0800142 if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
Andres Morales23974272015-05-14 22:42:26 -0700143 // to avoid accidental lockout, only count attempts that are long enough to be a
144 // real password. This may require some tweaking.
145 setPasswordEntryInputEnabled(true);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800146 onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
Rich Canningsf64ec632019-02-21 12:40:36 -0800147 Arrays.fill(entry, (byte) 0);
Andres Morales23974272015-05-14 22:42:26 -0700148 return;
149 }
150
Jorim Jaggid0565172016-09-15 16:31:14 -0700151 if (LatencyTracker.isEnabled(mContext)) {
152 LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
153 LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
154 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700155 mPendingLockCheck = LockPatternChecker.checkPassword(
156 mLockPatternUtils,
157 entry,
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800158 userId,
Xiyuan Xia6e380582015-05-05 15:16:08 -0700159 new LockPatternChecker.OnCheckCallback() {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700160
161 @Override
162 public void onEarlyMatched() {
Jorim Jaggid0565172016-09-15 16:31:14 -0700163 if (LatencyTracker.isEnabled(mContext)) {
164 LatencyTracker.getInstance(mContext).onActionEnd(
165 ACTION_CHECK_CREDENTIAL);
166 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700167 onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
168 true /* isValidPassword */);
Rich Canningsf64ec632019-02-21 12:40:36 -0800169 Arrays.fill(entry, (byte) 0);
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700170 }
171
Xiyuan Xia6e380582015-05-05 15:16:08 -0700172 @Override
Andres Morales23974272015-05-14 22:42:26 -0700173 public void onChecked(boolean matched, int timeoutMs) {
Jorim Jaggid0565172016-09-15 16:31:14 -0700174 if (LatencyTracker.isEnabled(mContext)) {
175 LatencyTracker.getInstance(mContext).onActionEnd(
176 ACTION_CHECK_CREDENTIAL_UNLOCKED);
177 }
Xiyuan Xiade26ea62015-05-19 15:00:41 -0700178 setPasswordEntryInputEnabled(true);
Xiyuan Xia6e380582015-05-05 15:16:08 -0700179 mPendingLockCheck = null;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700180 if (!matched) {
181 onPasswordChecked(userId, false /* matched */, timeoutMs,
182 true /* isValidPassword */);
183 }
Rich Canningsf64ec632019-02-21 12:40:36 -0800184 Arrays.fill(entry, (byte) 0);
Xiyuan Xia6e380582015-05-05 15:16:08 -0700185 }
Jorim Jaggied3032b2016-10-07 16:49:34 +0200186
187 @Override
188 public void onCancelled() {
189 // We already got dismissed with the early matched callback, so we cancelled
190 // the check. However, we still need to note down the latency.
191 if (LatencyTracker.isEnabled(mContext)) {
192 LatencyTracker.getInstance(mContext).onActionEnd(
193 ACTION_CHECK_CREDENTIAL_UNLOCKED);
194 }
Rich Canningsf64ec632019-02-21 12:40:36 -0800195 Arrays.fill(entry, (byte) 0);
Jorim Jaggied3032b2016-10-07 16:49:34 +0200196 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700197 });
198 }
199
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800200 private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
201 boolean isValidPassword) {
202 boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
Xiyuan Xia6e380582015-05-05 15:16:08 -0700203 if (matched) {
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800204 mCallback.reportUnlockAttempt(userId, true, 0);
205 if (dismissKeyguard) {
206 mDismissing = true;
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700207 mCallback.dismiss(true, userId);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800208 }
Jim Miller526ed2d2014-05-19 11:28:32 -0700209 } else {
Jim Miller51e3a672015-07-31 18:42:53 -0700210 if (isValidPassword) {
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800211 mCallback.reportUnlockAttempt(userId, false, timeoutMs);
Jim Miller51e3a672015-07-31 18:42:53 -0700212 if (timeoutMs > 0) {
213 long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800214 userId, timeoutMs);
Jim Miller51e3a672015-07-31 18:42:53 -0700215 handleAttemptLockout(deadline);
216 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400217 }
Jim Miller51e3a672015-07-31 18:42:53 -0700218 if (timeoutMs == 0) {
Adrian Roosdb327e92016-10-12 16:41:28 -0700219 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId());
Jim Miller51e3a672015-07-31 18:42:53 -0700220 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400221 }
Jim Miller4db942c2016-05-16 18:06:50 -0700222 resetPasswordText(true /* animate */, !matched /* announce deletion if no match */);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400223 }
224
Jim Miller4db942c2016-05-16 18:06:50 -0700225 protected abstract void resetPasswordText(boolean animate, boolean announce);
Rich Canningsf64ec632019-02-21 12:40:36 -0800226 protected abstract byte[] getPasswordText();
Selim Cinek4e8b9ed2014-06-20 16:37:04 -0700227 protected abstract void setPasswordEntryEnabled(boolean enabled);
Xiyuan Xiade26ea62015-05-19 15:00:41 -0700228 protected abstract void setPasswordEntryInputEnabled(boolean enabled);
Selim Cinek4e8b9ed2014-06-20 16:37:04 -0700229
Daniel Sandler69bdee72012-10-23 16:45:50 -0400230 // Prevent user from using the PIN/Password entry until scheduled deadline.
231 protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
Selim Cinek4e8b9ed2014-06-20 16:37:04 -0700232 setPasswordEntryEnabled(false);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400233 long elapsedRealtime = SystemClock.elapsedRealtime();
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200234 long secondsInFuture = (long) Math.ceil(
235 (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
236 mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
Daniel Sandler69bdee72012-10-23 16:45:50 -0400237
238 @Override
239 public void onTick(long millisUntilFinished) {
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200240 int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
Kevin Chyne01c5e12017-08-29 19:04:25 -0700241 mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
242 R.plurals.kg_too_many_failed_attempts_countdown,
243 secondsRemaining, secondsRemaining));
Daniel Sandler69bdee72012-10-23 16:45:50 -0400244 }
245
246 @Override
247 public void onFinish() {
Adrian Roosdb327e92016-10-12 16:41:28 -0700248 mSecurityMessageDisplay.setMessage("");
Daniel Sandler69bdee72012-10-23 16:45:50 -0400249 resetState();
250 }
251 }.start();
252 }
253
Xiyuan Xia09eb0332015-05-13 15:29:42 -0700254 protected void onUserInput() {
255 if (mCallback != null) {
256 mCallback.userActivity();
Lucas Dupinccf67212019-08-07 12:53:02 -0700257 mCallback.onUserInput();
Xiyuan Xia09eb0332015-05-13 15:29:42 -0700258 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700259 mSecurityMessageDisplay.setMessage("");
Xiyuan Xia09eb0332015-05-13 15:29:42 -0700260 }
261
Daniel Sandler69bdee72012-10-23 16:45:50 -0400262 @Override
263 public boolean onKeyDown(int keyCode, KeyEvent event) {
Lucas Dupin29e796d2018-05-10 15:31:20 -0700264 // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
265 // We don't want to consider it valid user input because the UI
266 // will already respond to the event.
267 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
268 onUserInput();
269 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400270 return false;
271 }
272
273 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -0400274 public boolean needsInput() {
275 return false;
276 }
277
278 @Override
279 public void onPause() {
lumarkd62bfd22019-01-10 15:29:11 +0800280 mResumed = false;
281
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200282 if (mCountdownTimer != null) {
283 mCountdownTimer.cancel();
284 mCountdownTimer = null;
285 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700286 if (mPendingLockCheck != null) {
287 mPendingLockCheck.cancel(false);
288 mPendingLockCheck = null;
289 }
Lucas Dupin2986c152018-04-09 20:49:41 -0700290 reset();
Daniel Sandler69bdee72012-10-23 16:45:50 -0400291 }
292
293 @Override
Chris Wrena042ac92012-11-07 11:37:06 -0500294 public void onResume(int reason) {
lumarkd62bfd22019-01-10 15:29:11 +0800295 mResumed = true;
Daniel Sandler69bdee72012-10-23 16:45:50 -0400296 }
297
298 @Override
299 public KeyguardSecurityCallback getCallback() {
300 return mCallback;
301 }
302
Selim Cinek3122fa82015-06-18 01:38:59 -0700303 @Override
304 public void showPromptReason(int reason) {
305 if (reason != PROMPT_REASON_NONE) {
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800306 int promtReasonStringRes = getPromptReasonStringRes(reason);
Selim Cinek3122fa82015-06-18 01:38:59 -0700307 if (promtReasonStringRes != 0) {
Adrian Roosdb327e92016-10-12 16:41:28 -0700308 mSecurityMessageDisplay.setMessage(promtReasonStringRes);
Selim Cinek3122fa82015-06-18 01:38:59 -0700309 }
310 }
311 }
312
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700313 @Override
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800314 public void showMessage(CharSequence message, ColorStateList colorState) {
Lucas Dupin51996bb2019-05-16 17:56:43 -0700315 if (colorState != null) {
316 mSecurityMessageDisplay.setNextMessageColor(colorState);
317 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700318 mSecurityMessageDisplay.setMessage(message);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700319 }
320
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800321 protected abstract int getPromptReasonStringRes(int reason);
Selim Cinek3122fa82015-06-18 01:38:59 -0700322
Daniel Sandleracb60fb2012-10-25 10:46:37 -0400323 // Cause a VIRTUAL_KEY vibration
324 public void doHapticKeyClick() {
325 if (mEnableHaptics) {
326 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
327 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
328 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
329 }
330 }
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500331
332 @Override
Jorim Jaggi76a16232014-08-08 17:00:47 +0200333 public boolean startDisappearAnimation(Runnable finishRunnable) {
334 return false;
335 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400336}
337