KeyguardAbsKeyInputView.java revision 25a272a9f6323f6a3513bb522d45e839449878ce
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.internal.policy.impl.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.R; 36import com.android.internal.widget.LockPatternUtils; 37 38/** 39 * Base class for PIN and password unlock screens. 40 */ 41public abstract class KeyguardAbsKeyInputView extends LinearLayout 42 implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { 43 protected KeyguardSecurityCallback mCallback; 44 protected TextView mPasswordEntry; 45 protected LockPatternUtils mLockPatternUtils; 46 protected SecurityMessageDisplay mSecurityMessageDisplay; 47 protected View mEcaView; 48 private Drawable mBouncerFrame; 49 protected boolean mEnableHaptics; 50 51 // To avoid accidental lockout due to events while the device in in the pocket, ignore 52 // any passwords with length less than or equal to this length. 53 protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; 54 55 public KeyguardAbsKeyInputView(Context context) { 56 this(context, null); 57 } 58 59 public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) { 60 super(context, attrs); 61 } 62 63 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 64 mCallback = callback; 65 } 66 67 public void setLockPatternUtils(LockPatternUtils utils) { 68 mLockPatternUtils = utils; 69 mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled(); 70 } 71 72 @Override 73 public void onWindowFocusChanged(boolean hasWindowFocus) { 74 if (hasWindowFocus) { 75 reset(); 76 } 77 } 78 79 public void reset() { 80 // start fresh 81 mPasswordEntry.setText(""); 82 mPasswordEntry.requestFocus(); 83 84 // if the user is currently locked out, enforce it. 85 long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); 86 if (deadline != 0) { 87 handleAttemptLockout(deadline); 88 } else { 89 resetState(); 90 } 91 } 92 93 protected abstract int getPasswordTextViewId(); 94 protected abstract void resetState(); 95 96 @Override 97 protected void onFinishInflate() { 98 mLockPatternUtils = new LockPatternUtils(mContext); 99 100 mPasswordEntry = (TextView) findViewById(getPasswordTextViewId()); 101 mPasswordEntry.setOnEditorActionListener(this); 102 mPasswordEntry.addTextChangedListener(this); 103 104 // Set selected property on so the view can send accessibility events. 105 mPasswordEntry.setSelected(true); 106 107 // Poke the wakelock any time the text is selected or modified 108 mPasswordEntry.setOnClickListener(new OnClickListener() { 109 public void onClick(View v) { 110 mCallback.userActivity(0); // TODO: customize timeout for text? 111 } 112 }); 113 114 mPasswordEntry.addTextChangedListener(new TextWatcher() { 115 public void onTextChanged(CharSequence s, int start, int before, int count) { 116 } 117 118 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 119 } 120 121 public void afterTextChanged(Editable s) { 122 if (mCallback != null) { 123 mCallback.userActivity(0); 124 } 125 } 126 }); 127 mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); 128 mEcaView = findViewById(R.id.keyguard_selector_fade_container); 129 View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame); 130 if (bouncerFrameView != null) { 131 mBouncerFrame = bouncerFrameView.getBackground(); 132 } 133 } 134 135 @Override 136 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 137 // send focus to the password field 138 return mPasswordEntry.requestFocus(direction, previouslyFocusedRect); 139 } 140 141 /* 142 * Override this if you have a different string for "wrong password" 143 * 144 * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this 145 */ 146 protected int getWrongPasswordStringId() { 147 return R.string.kg_wrong_password; 148 } 149 150 protected void verifyPasswordAndUnlock() { 151 String entry = mPasswordEntry.getText().toString(); 152 if (mLockPatternUtils.checkPassword(entry)) { 153 mCallback.reportSuccessfulUnlockAttempt(); 154 mCallback.dismiss(true); 155 } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { 156 // to avoid accidental lockout, only count attempts that are long enough to be a 157 // real password. This may require some tweaking. 158 mCallback.reportFailedUnlockAttempt(); 159 if (0 == (mCallback.getFailedAttempts() 160 % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { 161 long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); 162 handleAttemptLockout(deadline); 163 } 164 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true); 165 } 166 mPasswordEntry.setText(""); 167 } 168 169 // Prevent user from using the PIN/Password entry until scheduled deadline. 170 protected void handleAttemptLockout(long elapsedRealtimeDeadline) { 171 mPasswordEntry.setEnabled(false); 172 long elapsedRealtime = SystemClock.elapsedRealtime(); 173 new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { 174 175 @Override 176 public void onTick(long millisUntilFinished) { 177 int secondsRemaining = (int) (millisUntilFinished / 1000); 178 mSecurityMessageDisplay.setMessage( 179 R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining); 180 } 181 182 @Override 183 public void onFinish() { 184 mSecurityMessageDisplay.setMessage("", false); 185 resetState(); 186 } 187 }.start(); 188 } 189 190 @Override 191 public boolean onKeyDown(int keyCode, KeyEvent event) { 192 mCallback.userActivity(0); 193 return false; 194 } 195 196 @Override 197 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 198 // Check if this was the result of hitting the enter key 199 if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE 200 || actionId == EditorInfo.IME_ACTION_NEXT) { 201 verifyPasswordAndUnlock(); 202 return true; 203 } 204 return false; 205 } 206 207 @Override 208 public boolean needsInput() { 209 return false; 210 } 211 212 @Override 213 public void onPause() { 214 215 } 216 217 @Override 218 public void onResume(int reason) { 219 reset(); 220 } 221 222 @Override 223 public KeyguardSecurityCallback getCallback() { 224 return mCallback; 225 } 226 227 @Override 228 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 229 if (mCallback != null) { 230 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); 231 } 232 } 233 234 @Override 235 public void onTextChanged(CharSequence s, int start, int before, int count) { 236 } 237 238 @Override 239 public void afterTextChanged(Editable s) { 240 } 241 242 // Cause a VIRTUAL_KEY vibration 243 public void doHapticKeyClick() { 244 if (mEnableHaptics) { 245 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, 246 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING 247 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 248 } 249 } 250 251 @Override 252 public void showBouncer(int duration) { 253 KeyguardSecurityViewHelper. 254 showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); 255 } 256 257 @Override 258 public void hideBouncer(int duration) { 259 KeyguardSecurityViewHelper. 260 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); 261 } 262} 263 264