blob: a4b6958498c8e3b1f03bee3c88445d6bb0ccca42 [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;
Daniel Sandler69bdee72012-10-23 16:45:50 -040036
Rich Canningsf64ec632019-02-21 12:40:36 -080037import java.util.Arrays;
38
Daniel Sandler69bdee72012-10-23 16:45:50 -040039/**
40 * Base class for PIN and password unlock screens.
41 */
42public abstract class KeyguardAbsKeyInputView extends LinearLayout
Andrew Lee72b46d42015-01-30 13:23:21 -080043 implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
Daniel Sandler69bdee72012-10-23 16:45:50 -040044 protected KeyguardSecurityCallback mCallback;
Daniel Sandler69bdee72012-10-23 16:45:50 -040045 protected LockPatternUtils mLockPatternUtils;
Xiyuan Xia6e380582015-05-05 15:16:08 -070046 protected AsyncTask<?, ?, ?> mPendingLockCheck;
Daniel Sandler69bdee72012-10-23 16:45:50 -040047 protected SecurityMessageDisplay mSecurityMessageDisplay;
Chris Wrenc0ae9e62012-11-05 13:16:31 -050048 protected View mEcaView;
Daniel Sandleracb60fb2012-10-25 10:46:37 -040049 protected boolean mEnableHaptics;
Jim Millered7dcc22015-08-25 19:36:22 -070050 private boolean mDismissing;
lumarkd62bfd22019-01-10 15:29:11 +080051 protected boolean mResumed;
Hidenari Koshimae5be868c2014-08-21 11:27:33 +020052 private CountDownTimer mCountdownTimer = null;
Daniel Sandler69bdee72012-10-23 16:45:50 -040053
54 // To avoid accidental lockout due to events while the device in in the pocket, ignore
55 // any passwords with length less than or equal to this length.
56 protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
57
Daniel Sandler69bdee72012-10-23 16:45:50 -040058 public KeyguardAbsKeyInputView(Context context) {
59 this(context, null);
60 }
61
62 public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
63 super(context, attrs);
64 }
65
Jim Miller51e3a672015-07-31 18:42:53 -070066 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -040067 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
68 mCallback = callback;
69 }
70
Jim Miller51e3a672015-07-31 18:42:53 -070071 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -040072 public void setLockPatternUtils(LockPatternUtils utils) {
73 mLockPatternUtils = utils;
Daniel Sandleracb60fb2012-10-25 10:46:37 -040074 mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
Daniel Sandler69bdee72012-10-23 16:45:50 -040075 }
76
Jim Miller51e3a672015-07-31 18:42:53 -070077 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -040078 public void reset() {
79 // start fresh
Jim Millered7dcc22015-08-25 19:36:22 -070080 mDismissing = false;
Jim Miller4db942c2016-05-16 18:06:50 -070081 resetPasswordText(false /* animate */, false /* announce */);
Daniel Sandler69bdee72012-10-23 16:45:50 -040082 // if the user is currently locked out, enforce it.
Adrian Roos8150d2a2015-04-16 17:11:20 -070083 long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070084 KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7d5e00a2013-10-11 22:45:57 -070085 if (shouldLockout(deadline)) {
Daniel Sandler69bdee72012-10-23 16:45:50 -040086 handleAttemptLockout(deadline);
87 } else {
88 resetState();
89 }
90 }
91
Jim Miller7d5e00a2013-10-11 22:45:57 -070092 // Allow subclasses to override this behavior
93 protected boolean shouldLockout(long deadline) {
94 return deadline != 0;
95 }
96
Daniel Sandler8a26bf52012-10-30 13:29:50 -040097 protected abstract int getPasswordTextViewId();
Daniel Sandler69bdee72012-10-23 16:45:50 -040098 protected abstract void resetState();
99
100 @Override
101 protected void onFinishInflate() {
Daniel Sandleracb60fb2012-10-25 10:46:37 -0400102 mLockPatternUtils = new LockPatternUtils(mContext);
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500103 mEcaView = findViewById(R.id.keyguard_selector_fade_container);
Andrew Lee72b46d42015-01-30 13:23:21 -0800104
Alan Viverette51efddb2017-04-05 10:00:01 -0400105 EmergencyButton button = findViewById(R.id.emergency_call_button);
Andrew Leef98f7b92015-02-02 15:50:29 -0800106 if (button != null) {
107 button.setCallback(this);
108 }
Andrew Lee72b46d42015-01-30 13:23:21 -0800109 }
110
Jim Miller51e3a672015-07-31 18:42:53 -0700111 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700112 protected void onAttachedToWindow() {
113 super.onAttachedToWindow();
114 mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
115 }
116
117 @Override
Andrew Lee72b46d42015-01-30 13:23:21 -0800118 public void onEmergencyButtonClickedWhenInCall() {
119 mCallback.reset();
Daniel Sandler69bdee72012-10-23 16:45:50 -0400120 }
121
Daniel Sandler261b18a2012-11-01 23:54:03 -0400122 /*
123 * Override this if you have a different string for "wrong password"
124 *
125 * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
126 */
127 protected int getWrongPasswordStringId() {
128 return R.string.kg_wrong_password;
129 }
130
Daniel Sandler69bdee72012-10-23 16:45:50 -0400131 protected void verifyPasswordAndUnlock() {
Jim Millered7dcc22015-08-25 19:36:22 -0700132 if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
133
Rich Canningsf64ec632019-02-21 12:40:36 -0800134 final byte[] entry = getPasswordText();
Xiyuan Xiade26ea62015-05-19 15:00:41 -0700135 setPasswordEntryInputEnabled(false);
Xiyuan Xia6e380582015-05-05 15:16:08 -0700136 if (mPendingLockCheck != null) {
137 mPendingLockCheck.cancel(false);
138 }
Andres Morales23974272015-05-14 22:42:26 -0700139
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800140 final int userId = KeyguardUpdateMonitor.getCurrentUser();
Rich Canningsf64ec632019-02-21 12:40:36 -0800141 if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
Andres Morales23974272015-05-14 22:42:26 -0700142 // to avoid accidental lockout, only count attempts that are long enough to be a
143 // real password. This may require some tweaking.
144 setPasswordEntryInputEnabled(true);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800145 onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
Rich Canningsf64ec632019-02-21 12:40:36 -0800146 Arrays.fill(entry, (byte) 0);
Andres Morales23974272015-05-14 22:42:26 -0700147 return;
148 }
149
Jorim Jaggid0565172016-09-15 16:31:14 -0700150 if (LatencyTracker.isEnabled(mContext)) {
151 LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
152 LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
153 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700154 mPendingLockCheck = LockPatternChecker.checkPassword(
155 mLockPatternUtils,
156 entry,
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800157 userId,
Xiyuan Xia6e380582015-05-05 15:16:08 -0700158 new LockPatternChecker.OnCheckCallback() {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700159
160 @Override
161 public void onEarlyMatched() {
Jorim Jaggid0565172016-09-15 16:31:14 -0700162 if (LatencyTracker.isEnabled(mContext)) {
163 LatencyTracker.getInstance(mContext).onActionEnd(
164 ACTION_CHECK_CREDENTIAL);
165 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700166 onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
167 true /* isValidPassword */);
Rich Canningsf64ec632019-02-21 12:40:36 -0800168 Arrays.fill(entry, (byte) 0);
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700169 }
170
Xiyuan Xia6e380582015-05-05 15:16:08 -0700171 @Override
Andres Morales23974272015-05-14 22:42:26 -0700172 public void onChecked(boolean matched, int timeoutMs) {
Jorim Jaggid0565172016-09-15 16:31:14 -0700173 if (LatencyTracker.isEnabled(mContext)) {
174 LatencyTracker.getInstance(mContext).onActionEnd(
175 ACTION_CHECK_CREDENTIAL_UNLOCKED);
176 }
Xiyuan Xiade26ea62015-05-19 15:00:41 -0700177 setPasswordEntryInputEnabled(true);
Xiyuan Xia6e380582015-05-05 15:16:08 -0700178 mPendingLockCheck = null;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700179 if (!matched) {
180 onPasswordChecked(userId, false /* matched */, timeoutMs,
181 true /* isValidPassword */);
182 }
Rich Canningsf64ec632019-02-21 12:40:36 -0800183 Arrays.fill(entry, (byte) 0);
Xiyuan Xia6e380582015-05-05 15:16:08 -0700184 }
Jorim Jaggied3032b2016-10-07 16:49:34 +0200185
186 @Override
187 public void onCancelled() {
188 // We already got dismissed with the early matched callback, so we cancelled
189 // the check. However, we still need to note down the latency.
190 if (LatencyTracker.isEnabled(mContext)) {
191 LatencyTracker.getInstance(mContext).onActionEnd(
192 ACTION_CHECK_CREDENTIAL_UNLOCKED);
193 }
Rich Canningsf64ec632019-02-21 12:40:36 -0800194 Arrays.fill(entry, (byte) 0);
Jorim Jaggied3032b2016-10-07 16:49:34 +0200195 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700196 });
197 }
198
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800199 private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
200 boolean isValidPassword) {
201 boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
Xiyuan Xia6e380582015-05-05 15:16:08 -0700202 if (matched) {
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800203 mCallback.reportUnlockAttempt(userId, true, 0);
204 if (dismissKeyguard) {
205 mDismissing = true;
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700206 mCallback.dismiss(true, userId);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800207 }
Jim Miller526ed2d2014-05-19 11:28:32 -0700208 } else {
Jim Miller51e3a672015-07-31 18:42:53 -0700209 if (isValidPassword) {
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800210 mCallback.reportUnlockAttempt(userId, false, timeoutMs);
Jim Miller51e3a672015-07-31 18:42:53 -0700211 if (timeoutMs > 0) {
212 long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800213 userId, timeoutMs);
Jim Miller51e3a672015-07-31 18:42:53 -0700214 handleAttemptLockout(deadline);
215 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400216 }
Jim Miller51e3a672015-07-31 18:42:53 -0700217 if (timeoutMs == 0) {
Adrian Roosdb327e92016-10-12 16:41:28 -0700218 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId());
Jim Miller51e3a672015-07-31 18:42:53 -0700219 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400220 }
Jim Miller4db942c2016-05-16 18:06:50 -0700221 resetPasswordText(true /* animate */, !matched /* announce deletion if no match */);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400222 }
223
Jim Miller4db942c2016-05-16 18:06:50 -0700224 protected abstract void resetPasswordText(boolean animate, boolean announce);
Rich Canningsf64ec632019-02-21 12:40:36 -0800225 protected abstract byte[] getPasswordText();
Selim Cinek4e8b9ed2014-06-20 16:37:04 -0700226 protected abstract void setPasswordEntryEnabled(boolean enabled);
Xiyuan Xiade26ea62015-05-19 15:00:41 -0700227 protected abstract void setPasswordEntryInputEnabled(boolean enabled);
Selim Cinek4e8b9ed2014-06-20 16:37:04 -0700228
Daniel Sandler69bdee72012-10-23 16:45:50 -0400229 // Prevent user from using the PIN/Password entry until scheduled deadline.
230 protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
Selim Cinek4e8b9ed2014-06-20 16:37:04 -0700231 setPasswordEntryEnabled(false);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400232 long elapsedRealtime = SystemClock.elapsedRealtime();
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200233 long secondsInFuture = (long) Math.ceil(
234 (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
235 mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
Daniel Sandler69bdee72012-10-23 16:45:50 -0400236
237 @Override
238 public void onTick(long millisUntilFinished) {
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200239 int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
Kevin Chyne01c5e12017-08-29 19:04:25 -0700240 mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
241 R.plurals.kg_too_many_failed_attempts_countdown,
242 secondsRemaining, secondsRemaining));
Daniel Sandler69bdee72012-10-23 16:45:50 -0400243 }
244
245 @Override
246 public void onFinish() {
Adrian Roosdb327e92016-10-12 16:41:28 -0700247 mSecurityMessageDisplay.setMessage("");
Daniel Sandler69bdee72012-10-23 16:45:50 -0400248 resetState();
249 }
250 }.start();
251 }
252
Xiyuan Xia09eb0332015-05-13 15:29:42 -0700253 protected void onUserInput() {
254 if (mCallback != null) {
255 mCallback.userActivity();
256 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700257 mSecurityMessageDisplay.setMessage("");
Xiyuan Xia09eb0332015-05-13 15:29:42 -0700258 }
259
Daniel Sandler69bdee72012-10-23 16:45:50 -0400260 @Override
261 public boolean onKeyDown(int keyCode, KeyEvent event) {
Lucas Dupin29e796d2018-05-10 15:31:20 -0700262 // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
263 // We don't want to consider it valid user input because the UI
264 // will already respond to the event.
265 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
266 onUserInput();
267 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400268 return false;
269 }
270
271 @Override
Daniel Sandler69bdee72012-10-23 16:45:50 -0400272 public boolean needsInput() {
273 return false;
274 }
275
276 @Override
277 public void onPause() {
lumarkd62bfd22019-01-10 15:29:11 +0800278 mResumed = false;
279
Hidenari Koshimae5be868c2014-08-21 11:27:33 +0200280 if (mCountdownTimer != null) {
281 mCountdownTimer.cancel();
282 mCountdownTimer = null;
283 }
Xiyuan Xia6e380582015-05-05 15:16:08 -0700284 if (mPendingLockCheck != null) {
285 mPendingLockCheck.cancel(false);
286 mPendingLockCheck = null;
287 }
Lucas Dupin2986c152018-04-09 20:49:41 -0700288 reset();
Daniel Sandler69bdee72012-10-23 16:45:50 -0400289 }
290
291 @Override
Chris Wrena042ac92012-11-07 11:37:06 -0500292 public void onResume(int reason) {
lumarkd62bfd22019-01-10 15:29:11 +0800293 mResumed = true;
Daniel Sandler69bdee72012-10-23 16:45:50 -0400294 }
295
296 @Override
297 public KeyguardSecurityCallback getCallback() {
298 return mCallback;
299 }
300
Selim Cinek3122fa82015-06-18 01:38:59 -0700301 @Override
302 public void showPromptReason(int reason) {
303 if (reason != PROMPT_REASON_NONE) {
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800304 int promtReasonStringRes = getPromptReasonStringRes(reason);
Selim Cinek3122fa82015-06-18 01:38:59 -0700305 if (promtReasonStringRes != 0) {
Adrian Roosdb327e92016-10-12 16:41:28 -0700306 mSecurityMessageDisplay.setMessage(promtReasonStringRes);
Selim Cinek3122fa82015-06-18 01:38:59 -0700307 }
308 }
309 }
310
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700311 @Override
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800312 public void showMessage(CharSequence message, ColorStateList colorState) {
Lucas Dupin51996bb2019-05-16 17:56:43 -0700313 if (colorState != null) {
314 mSecurityMessageDisplay.setNextMessageColor(colorState);
315 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700316 mSecurityMessageDisplay.setMessage(message);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700317 }
318
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800319 protected abstract int getPromptReasonStringRes(int reason);
Selim Cinek3122fa82015-06-18 01:38:59 -0700320
Daniel Sandleracb60fb2012-10-25 10:46:37 -0400321 // Cause a VIRTUAL_KEY vibration
322 public void doHapticKeyClick() {
323 if (mEnableHaptics) {
324 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
325 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
326 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
327 }
328 }
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500329
330 @Override
Jorim Jaggi76a16232014-08-08 17:00:47 +0200331 public boolean startDisappearAnimation(Runnable finishRunnable) {
332 return false;
333 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400334}
335