KeyguardAbsKeyInputView.java revision 5ecd81154fa039961f65bb4e36d18ac555b0d1d6
1/* 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 17package com.android.keyguard; 18 19import android.content.Context; 20import android.graphics.Rect; 21import android.graphics.drawable.Drawable; 22import android.os.CountDownTimer; 23import android.os.SystemClock; 24import android.text.Editable; 25import android.text.TextWatcher; 26import android.util.AttributeSet; 27import android.view.HapticFeedbackConstants; 28import android.view.KeyEvent; 29import android.view.View; 30import android.view.inputmethod.EditorInfo; 31import android.widget.LinearLayout; 32import android.widget.TextView; 33import android.widget.TextView.OnEditorActionListener; 34 35import com.android.internal.widget.LockPatternUtils; 36 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; 43 protected TextView mPasswordEntry; 44 protected LockPatternUtils mLockPatternUtils; 45 protected SecurityMessageDisplay mSecurityMessageDisplay; 46 protected View mEcaView; 47 private Drawable mBouncerFrame; 48 protected boolean mEnableHaptics; 49 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 54 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; 68 mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled(); 69 } 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 92 protected abstract int getPasswordTextViewId(); 93 protected abstract void resetState(); 94 95 @Override 96 protected void onFinishInflate() { 97 mLockPatternUtils = new LockPatternUtils(mContext); 98 99 mPasswordEntry = (TextView) findViewById(getPasswordTextViewId()); 100 mPasswordEntry.setOnEditorActionListener(this); 101 mPasswordEntry.addTextChangedListener(this); 102 103 // Set selected property on so the view can send accessibility events. 104 mPasswordEntry.setSelected(true); 105 106 // 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 }); 126 mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); 127 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 } 132 } 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 140 /* 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 149 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 } 163 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true); 164 } 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() { 183 mSecurityMessageDisplay.setMessage("", false); 184 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 217 public void onResume(int reason) { 218 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 241 // 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 } 249 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 } 261} 262 263