blob: fb2eeda1a7ae7d588ddeda80c4f05d20b4b30815 [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();
85 if (deadline != 0) {
86 handleAttemptLockout(deadline);
87 } else {
88 resetState();
89 }
90 }
91
Daniel Sandler8a26bf52012-10-30 13:29:50 -040092 protected abstract int getPasswordTextViewId();
Daniel Sandler69bdee72012-10-23 16:45:50 -040093 protected abstract void resetState();
94
95 @Override
96 protected void onFinishInflate() {
Daniel Sandleracb60fb2012-10-25 10:46:37 -040097 mLockPatternUtils = new LockPatternUtils(mContext);
Daniel Sandler69bdee72012-10-23 16:45:50 -040098
Daniel Sandler8a26bf52012-10-30 13:29:50 -040099 mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
Daniel Sandler69bdee72012-10-23 16:45:50 -0400100 mPasswordEntry.setOnEditorActionListener(this);
101 mPasswordEntry.addTextChangedListener(this);
102
alanvc7375af2012-10-30 17:07:37 -0700103 // Set selected property on so the view can send accessibility events.
104 mPasswordEntry.setSelected(true);
105
Daniel Sandler69bdee72012-10-23 16:45:50 -0400106 // Poke the wakelock any time the text is selected or modified
107 mPasswordEntry.setOnClickListener(new OnClickListener() {
108 public void onClick(View v) {
109 mCallback.userActivity(0); // TODO: customize timeout for text?
110 }
111 });
112
113 mPasswordEntry.addTextChangedListener(new TextWatcher() {
114 public void onTextChanged(CharSequence s, int start, int before, int count) {
115 }
116
117 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
118 }
119
120 public void afterTextChanged(Editable s) {
121 if (mCallback != null) {
122 mCallback.userActivity(0);
123 }
124 }
125 });
Jim Miller0b728242012-10-28 19:42:30 -0700126 mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500127 mEcaView = findViewById(R.id.keyguard_selector_fade_container);
128 View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
129 if (bouncerFrameView != null) {
130 mBouncerFrame = bouncerFrameView.getBackground();
131 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400132 }
133
134 @Override
135 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
136 // send focus to the password field
137 return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
138 }
139
Daniel Sandler261b18a2012-11-01 23:54:03 -0400140 /*
141 * Override this if you have a different string for "wrong password"
142 *
143 * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
144 */
145 protected int getWrongPasswordStringId() {
146 return R.string.kg_wrong_password;
147 }
148
Daniel Sandler69bdee72012-10-23 16:45:50 -0400149 protected void verifyPasswordAndUnlock() {
150 String entry = mPasswordEntry.getText().toString();
151 if (mLockPatternUtils.checkPassword(entry)) {
152 mCallback.reportSuccessfulUnlockAttempt();
153 mCallback.dismiss(true);
154 } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
155 // to avoid accidental lockout, only count attempts that are long enough to be a
156 // real password. This may require some tweaking.
157 mCallback.reportFailedUnlockAttempt();
158 if (0 == (mCallback.getFailedAttempts()
159 % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
160 long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
161 handleAttemptLockout(deadline);
162 }
Daniel Sandler16d90922012-11-01 12:41:14 -0400163 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400164 }
165 mPasswordEntry.setText("");
166 }
167
168 // Prevent user from using the PIN/Password entry until scheduled deadline.
169 protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
170 mPasswordEntry.setEnabled(false);
171 long elapsedRealtime = SystemClock.elapsedRealtime();
172 new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
173
174 @Override
175 public void onTick(long millisUntilFinished) {
176 int secondsRemaining = (int) (millisUntilFinished / 1000);
177 mSecurityMessageDisplay.setMessage(
178 R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
179 }
180
181 @Override
182 public void onFinish() {
Daniel Sandler6a64ac52012-11-01 11:58:13 -0400183 mSecurityMessageDisplay.setMessage("", false);
Daniel Sandler69bdee72012-10-23 16:45:50 -0400184 resetState();
185 }
186 }.start();
187 }
188
189 @Override
190 public boolean onKeyDown(int keyCode, KeyEvent event) {
191 mCallback.userActivity(0);
192 return false;
193 }
194
195 @Override
196 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
197 // Check if this was the result of hitting the enter key
198 if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
199 || actionId == EditorInfo.IME_ACTION_NEXT) {
200 verifyPasswordAndUnlock();
201 return true;
202 }
203 return false;
204 }
205
206 @Override
207 public boolean needsInput() {
208 return false;
209 }
210
211 @Override
212 public void onPause() {
213
214 }
215
216 @Override
Chris Wrena042ac92012-11-07 11:37:06 -0500217 public void onResume(int reason) {
Daniel Sandler69bdee72012-10-23 16:45:50 -0400218 reset();
219 }
220
221 @Override
222 public KeyguardSecurityCallback getCallback() {
223 return mCallback;
224 }
225
226 @Override
227 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
228 if (mCallback != null) {
229 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
230 }
231 }
232
233 @Override
234 public void onTextChanged(CharSequence s, int start, int before, int count) {
235 }
236
237 @Override
238 public void afterTextChanged(Editable s) {
239 }
240
Daniel Sandleracb60fb2012-10-25 10:46:37 -0400241 // Cause a VIRTUAL_KEY vibration
242 public void doHapticKeyClick() {
243 if (mEnableHaptics) {
244 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
245 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
246 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
247 }
248 }
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500249
250 @Override
251 public void showBouncer(int duration) {
252 KeyguardSecurityViewHelper.
253 showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
254 }
255
256 @Override
257 public void hideBouncer(int duration) {
258 KeyguardSecurityViewHelper.
259 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
260 }
Daniel Sandler69bdee72012-10-23 16:45:50 -0400261}
262