blob: 395015911338b503986b0e0cb73115b6a0ef8f61 [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
19import android.content.Context;
Daniel Sandler69bdee72012-10-23 16:45:50 -040020import android.graphics.Rect;
Chris Wrenc0ae9e62012-11-05 13:16:31 -050021import android.graphics.drawable.Drawable;
Daniel Sandler69bdee72012-10-23 16:45:50 -040022import android.os.CountDownTimer;
23import android.os.SystemClock;
24import android.text.Editable;
Daniel Sandler69bdee72012-10-23 16:45:50 -040025import android.text.TextWatcher;
Michael Jurka1254f2f2012-10-25 11:44:31 -070026import android.util.AttributeSet;
27import android.view.HapticFeedbackConstants;
Daniel Sandler69bdee72012-10-23 16:45:50 -040028import android.view.KeyEvent;
Michael Jurka1254f2f2012-10-25 11:44:31 -070029import android.view.View;
Daniel Sandler69bdee72012-10-23 16:45:50 -040030import android.view.inputmethod.EditorInfo;
Daniel Sandler69bdee72012-10-23 16:45:50 -040031import android.widget.LinearLayout;
32import android.widget.TextView;
33import android.widget.TextView.OnEditorActionListener;
34
Michael Jurka1254f2f2012-10-25 11:44:31 -070035import com.android.internal.widget.LockPatternUtils;
Daniel Sandler69bdee72012-10-23 16:45:50 -040036
37/**
38 * Base class for PIN and password unlock screens.
39 */
40public abstract class KeyguardAbsKeyInputView extends LinearLayout
41 implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
42 protected KeyguardSecurityCallback mCallback;
Daniel Sandlerd5692742012-10-24 00:21:32 -040043 protected TextView mPasswordEntry;
Daniel Sandler69bdee72012-10-23 16:45:50 -040044 protected LockPatternUtils mLockPatternUtils;
45 protected SecurityMessageDisplay mSecurityMessageDisplay;
Chris Wrenc0ae9e62012-11-05 13:16:31 -050046 protected View mEcaView;
47 private Drawable mBouncerFrame;
Daniel Sandleracb60fb2012-10-25 10:46:37 -040048 protected boolean mEnableHaptics;
Daniel Sandler69bdee72012-10-23 16:45:50 -040049
50 // To avoid accidental lockout due to events while the device in in the pocket, ignore
51 // any passwords with length less than or equal to this length.
52 protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
53
Daniel Sandler69bdee72012-10-23 16:45:50 -040054 public KeyguardAbsKeyInputView(Context context) {
55 this(context, null);
56 }
57
58 public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
59 super(context, attrs);
60 }
61
62 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
63 mCallback = callback;
64 }
65
66 public void setLockPatternUtils(LockPatternUtils utils) {
67 mLockPatternUtils = utils;
Daniel Sandleracb60fb2012-10-25 10:46:37 -040068 mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
Daniel Sandler69bdee72012-10-23 16:45:50 -040069 }
70
71 @Override
72 public void onWindowFocusChanged(boolean hasWindowFocus) {
73 if (hasWindowFocus) {
74 reset();
75 }
76 }
77
78 public void reset() {
79 // start fresh
80 mPasswordEntry.setText("");
81 mPasswordEntry.requestFocus();
82
83 // if the user is currently locked out, enforce it.
84 long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
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);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400103
Daniel Sandler8a26bf52012-10-30 13:29:50 -0400104 mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
Daniel Sandler69bdee72012-10-23 16:45:50 -0400105 mPasswordEntry.setOnEditorActionListener(this);
106 mPasswordEntry.addTextChangedListener(this);
107
alanvc7375af2012-10-30 17:07:37 -0700108 // Set selected property on so the view can send accessibility events.
109 mPasswordEntry.setSelected(true);
110
Daniel Sandler69bdee72012-10-23 16:45:50 -0400111 // Poke the wakelock any time the text is selected or modified
112 mPasswordEntry.setOnClickListener(new OnClickListener() {
113 public void onClick(View v) {
114 mCallback.userActivity(0); // TODO: customize timeout for text?
115 }
116 });
117
118 mPasswordEntry.addTextChangedListener(new TextWatcher() {
119 public void onTextChanged(CharSequence s, int start, int before, int count) {
120 }
121
122 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
123 }
124
125 public void afterTextChanged(Editable s) {
126 if (mCallback != null) {
127 mCallback.userActivity(0);
128 }
129 }
130 });
Jim Miller0b728242012-10-28 19:42:30 -0700131 mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500132 mEcaView = findViewById(R.id.keyguard_selector_fade_container);
133 View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
134 if (bouncerFrameView != null) {
135 mBouncerFrame = bouncerFrameView.getBackground();
136 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400137 }
138
139 @Override
140 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
141 // send focus to the password field
142 return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
143 }
144
Daniel Sandler261b18a2012-11-01 23:54:03 -0400145 /*
146 * Override this if you have a different string for "wrong password"
147 *
148 * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
149 */
150 protected int getWrongPasswordStringId() {
151 return R.string.kg_wrong_password;
152 }
153
Daniel Sandler69bdee72012-10-23 16:45:50 -0400154 protected void verifyPasswordAndUnlock() {
155 String entry = mPasswordEntry.getText().toString();
156 if (mLockPatternUtils.checkPassword(entry)) {
Jim Miller7751ff62014-01-14 18:57:03 -0800157 mCallback.reportUnlockAttempt(true);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400158 mCallback.dismiss(true);
159 } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
160 // to avoid accidental lockout, only count attempts that are long enough to be a
161 // real password. This may require some tweaking.
Jim Miller7751ff62014-01-14 18:57:03 -0800162 mCallback.reportUnlockAttempt(false);
163 int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
164 if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
Daniel Sandler69bdee72012-10-23 16:45:50 -0400165 long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
166 handleAttemptLockout(deadline);
167 }
Daniel Sandler16d90922012-11-01 12:41:14 -0400168 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400169 }
170 mPasswordEntry.setText("");
171 }
172
173 // Prevent user from using the PIN/Password entry until scheduled deadline.
174 protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
175 mPasswordEntry.setEnabled(false);
176 long elapsedRealtime = SystemClock.elapsedRealtime();
177 new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
178
179 @Override
180 public void onTick(long millisUntilFinished) {
181 int secondsRemaining = (int) (millisUntilFinished / 1000);
182 mSecurityMessageDisplay.setMessage(
183 R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
184 }
185
186 @Override
187 public void onFinish() {
Daniel Sandler6a64ac52012-11-01 11:58:13 -0400188 mSecurityMessageDisplay.setMessage("", false);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400189 resetState();
190 }
191 }.start();
192 }
193
194 @Override
195 public boolean onKeyDown(int keyCode, KeyEvent event) {
196 mCallback.userActivity(0);
197 return false;
198 }
199
200 @Override
201 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
202 // Check if this was the result of hitting the enter key
203 if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
204 || actionId == EditorInfo.IME_ACTION_NEXT) {
205 verifyPasswordAndUnlock();
206 return true;
207 }
208 return false;
209 }
210
211 @Override
212 public boolean needsInput() {
213 return false;
214 }
215
216 @Override
217 public void onPause() {
218
219 }
220
221 @Override
Chris Wrena042ac92012-11-07 11:37:06 -0500222 public void onResume(int reason) {
Daniel Sandler69bdee72012-10-23 16:45:50 -0400223 reset();
224 }
225
226 @Override
227 public KeyguardSecurityCallback getCallback() {
228 return mCallback;
229 }
230
231 @Override
232 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
233 if (mCallback != null) {
234 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
235 }
236 }
237
238 @Override
239 public void onTextChanged(CharSequence s, int start, int before, int count) {
240 }
241
242 @Override
243 public void afterTextChanged(Editable s) {
244 }
245
Daniel Sandleracb60fb2012-10-25 10:46:37 -0400246 // Cause a VIRTUAL_KEY vibration
247 public void doHapticKeyClick() {
248 if (mEnableHaptics) {
249 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
250 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
251 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
252 }
253 }
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500254
255 @Override
256 public void showBouncer(int duration) {
257 KeyguardSecurityViewHelper.
258 showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
259 }
260
261 @Override
262 public void hideBouncer(int duration) {
263 KeyguardSecurityViewHelper.
264 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
265 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400266}
267