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 17 package com.android.keyguard; 18 19 import android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.os.CountDownTimer; 22 import android.os.SystemClock; 23 import android.util.AttributeSet; 24 import android.view.HapticFeedbackConstants; 25 import android.view.KeyEvent; 26 import android.view.View; 27 import android.widget.LinearLayout; 28 29 import com.android.internal.widget.LockPatternUtils; 30 31 /** 32 * Base class for PIN and password unlock screens. 33 */ 34 public abstract class KeyguardAbsKeyInputView extends LinearLayout 35 implements KeyguardSecurityView { 36 protected KeyguardSecurityCallback mCallback; 37 protected LockPatternUtils mLockPatternUtils; 38 protected SecurityMessageDisplay mSecurityMessageDisplay; 39 protected View mEcaView; 40 private Drawable mBouncerFrame; 41 protected boolean mEnableHaptics; 42 43 // To avoid accidental lockout due to events while the device in in the pocket, ignore 44 // any passwords with length less than or equal to this length. 45 protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; 46 47 public KeyguardAbsKeyInputView(Context context) { 48 this(context, null); 49 } 50 51 public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) { 52 super(context, attrs); 53 } 54 55 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 56 mCallback = callback; 57 } 58 59 public void setLockPatternUtils(LockPatternUtils utils) { 60 mLockPatternUtils = utils; 61 mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled(); 62 } 63 64 public void reset() { 65 // start fresh 66 resetPasswordText(false /* animate */); 67 // if the user is currently locked out, enforce it. 68 long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); 69 if (shouldLockout(deadline)) { 70 handleAttemptLockout(deadline); 71 } else { 72 resetState(); 73 } 74 } 75 76 // Allow subclasses to override this behavior 77 protected boolean shouldLockout(long deadline) { 78 return deadline != 0; 79 } 80 81 protected abstract int getPasswordTextViewId(); 82 protected abstract void resetState(); 83 84 @Override 85 protected void onFinishInflate() { 86 mLockPatternUtils = new LockPatternUtils(mContext); 87 mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); 88 mEcaView = findViewById(R.id.keyguard_selector_fade_container); 89 View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame); 90 if (bouncerFrameView != null) { 91 mBouncerFrame = bouncerFrameView.getBackground(); 92 } 93 } 94 95 /* 96 * Override this if you have a different string for "wrong password" 97 * 98 * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this 99 */ 100 protected int getWrongPasswordStringId() { 101 return R.string.kg_wrong_password; 102 } 103 104 protected void verifyPasswordAndUnlock() { 105 String entry = getPasswordText(); 106 if (mLockPatternUtils.checkPassword(entry)) { 107 mCallback.reportUnlockAttempt(true); 108 mCallback.dismiss(true); 109 } else { 110 if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { 111 // to avoid accidental lockout, only count attempts that are long enough to be a 112 // real password. This may require some tweaking. 113 mCallback.reportUnlockAttempt(false); 114 int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); 115 if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { 116 long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); 117 handleAttemptLockout(deadline); 118 } 119 } 120 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true); 121 } 122 resetPasswordText(true /* animate */); 123 } 124 125 protected abstract void resetPasswordText(boolean animate); 126 protected abstract String getPasswordText(); 127 protected abstract void setPasswordEntryEnabled(boolean enabled); 128 129 // Prevent user from using the PIN/Password entry until scheduled deadline. 130 protected void handleAttemptLockout(long elapsedRealtimeDeadline) { 131 setPasswordEntryEnabled(false); 132 long elapsedRealtime = SystemClock.elapsedRealtime(); 133 new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { 134 135 @Override 136 public void onTick(long millisUntilFinished) { 137 int secondsRemaining = (int) (millisUntilFinished / 1000); 138 mSecurityMessageDisplay.setMessage( 139 R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining); 140 } 141 142 @Override 143 public void onFinish() { 144 mSecurityMessageDisplay.setMessage("", false); 145 resetState(); 146 } 147 }.start(); 148 } 149 150 @Override 151 public boolean onKeyDown(int keyCode, KeyEvent event) { 152 mCallback.userActivity(); 153 return false; 154 } 155 156 @Override 157 public boolean needsInput() { 158 return false; 159 } 160 161 @Override 162 public void onPause() { 163 164 } 165 166 @Override 167 public void onResume(int reason) { 168 reset(); 169 } 170 171 @Override 172 public KeyguardSecurityCallback getCallback() { 173 return mCallback; 174 } 175 176 // Cause a VIRTUAL_KEY vibration 177 public void doHapticKeyClick() { 178 if (mEnableHaptics) { 179 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, 180 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING 181 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 182 } 183 } 184 185 @Override 186 public void showBouncer(int duration) { 187 KeyguardSecurityViewHelper. 188 showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); 189 } 190 191 @Override 192 public void hideBouncer(int duration) { 193 KeyguardSecurityViewHelper. 194 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); 195 } 196 197 @Override 198 public boolean startDisappearAnimation(Runnable finishRunnable) { 199 return false; 200 } 201 } 202 203