• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.AsyncTask;
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.LockPatternChecker;
30 import com.android.internal.widget.LockPatternUtils;
31 
32 /**
33  * Base class for PIN and password unlock screens.
34  */
35 public abstract class KeyguardAbsKeyInputView extends LinearLayout
36         implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
37     protected KeyguardSecurityCallback mCallback;
38     protected LockPatternUtils mLockPatternUtils;
39     protected AsyncTask<?, ?, ?> mPendingLockCheck;
40     protected SecurityMessageDisplay mSecurityMessageDisplay;
41     protected View mEcaView;
42     protected boolean mEnableHaptics;
43     private boolean mDismissing;
44 
45     // To avoid accidental lockout due to events while the device in in the pocket, ignore
46     // any passwords with length less than or equal to this length.
47     protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
48 
KeyguardAbsKeyInputView(Context context)49     public KeyguardAbsKeyInputView(Context context) {
50         this(context, null);
51     }
52 
KeyguardAbsKeyInputView(Context context, AttributeSet attrs)53     public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
54         super(context, attrs);
55     }
56 
57     @Override
setKeyguardCallback(KeyguardSecurityCallback callback)58     public void setKeyguardCallback(KeyguardSecurityCallback callback) {
59         mCallback = callback;
60     }
61 
62     @Override
setLockPatternUtils(LockPatternUtils utils)63     public void setLockPatternUtils(LockPatternUtils utils) {
64         mLockPatternUtils = utils;
65         mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
66     }
67 
68     @Override
reset()69     public void reset() {
70         // start fresh
71         mDismissing = false;
72         resetPasswordText(false /* animate */);
73         // if the user is currently locked out, enforce it.
74         long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
75                 KeyguardUpdateMonitor.getCurrentUser());
76         if (shouldLockout(deadline)) {
77             handleAttemptLockout(deadline);
78         } else {
79             resetState();
80         }
81     }
82 
83     // Allow subclasses to override this behavior
shouldLockout(long deadline)84     protected boolean shouldLockout(long deadline) {
85         return deadline != 0;
86     }
87 
getPasswordTextViewId()88     protected abstract int getPasswordTextViewId();
resetState()89     protected abstract void resetState();
90 
91     @Override
onFinishInflate()92     protected void onFinishInflate() {
93         mLockPatternUtils = new LockPatternUtils(mContext);
94         mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
95         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
96 
97         EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button);
98         if (button != null) {
99             button.setCallback(this);
100         }
101     }
102 
103     @Override
onEmergencyButtonClickedWhenInCall()104     public void onEmergencyButtonClickedWhenInCall() {
105         mCallback.reset();
106     }
107 
108     /*
109      * Override this if you have a different string for "wrong password"
110      *
111      * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
112      */
getWrongPasswordStringId()113     protected int getWrongPasswordStringId() {
114         return R.string.kg_wrong_password;
115     }
116 
verifyPasswordAndUnlock()117     protected void verifyPasswordAndUnlock() {
118         if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
119 
120         final String entry = getPasswordText();
121         setPasswordEntryInputEnabled(false);
122         if (mPendingLockCheck != null) {
123             mPendingLockCheck.cancel(false);
124         }
125 
126         if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
127             // to avoid accidental lockout, only count attempts that are long enough to be a
128             // real password. This may require some tweaking.
129             setPasswordEntryInputEnabled(true);
130             onPasswordChecked(false /* matched */, 0, false /* not valid - too short */);
131             return;
132         }
133 
134         mPendingLockCheck = LockPatternChecker.checkPassword(
135                 mLockPatternUtils,
136                 entry,
137                 KeyguardUpdateMonitor.getCurrentUser(),
138                 new LockPatternChecker.OnCheckCallback() {
139                     @Override
140                     public void onChecked(boolean matched, int timeoutMs) {
141                         setPasswordEntryInputEnabled(true);
142                         mPendingLockCheck = null;
143                         onPasswordChecked(matched, timeoutMs, true /* isValidPassword */);
144                     }
145                 });
146     }
147 
onPasswordChecked(boolean matched, int timeoutMs, boolean isValidPassword)148     private void onPasswordChecked(boolean matched, int timeoutMs, boolean isValidPassword) {
149         if (matched) {
150             mDismissing = true;
151             mCallback.reportUnlockAttempt(true, 0);
152             mCallback.dismiss(true);
153         } else {
154             if (isValidPassword) {
155                 mCallback.reportUnlockAttempt(false, timeoutMs);
156                 if (timeoutMs > 0) {
157                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
158                             KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
159                     handleAttemptLockout(deadline);
160                 }
161             }
162             if (timeoutMs == 0) {
163                 mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
164             }
165         }
166         resetPasswordText(true /* animate */);
167     }
168 
resetPasswordText(boolean animate)169     protected abstract void resetPasswordText(boolean animate);
getPasswordText()170     protected abstract String getPasswordText();
setPasswordEntryEnabled(boolean enabled)171     protected abstract void setPasswordEntryEnabled(boolean enabled);
setPasswordEntryInputEnabled(boolean enabled)172     protected abstract void setPasswordEntryInputEnabled(boolean enabled);
173 
174     // Prevent user from using the PIN/Password entry until scheduled deadline.
handleAttemptLockout(long elapsedRealtimeDeadline)175     protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
176         setPasswordEntryEnabled(false);
177         long elapsedRealtime = SystemClock.elapsedRealtime();
178         new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
179 
180             @Override
181             public void onTick(long millisUntilFinished) {
182                 int secondsRemaining = (int) (millisUntilFinished / 1000);
183                 mSecurityMessageDisplay.setMessage(
184                         R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
185             }
186 
187             @Override
188             public void onFinish() {
189                 mSecurityMessageDisplay.setMessage("", false);
190                 resetState();
191             }
192         }.start();
193     }
194 
onUserInput()195     protected void onUserInput() {
196         if (mCallback != null) {
197             mCallback.userActivity();
198         }
199         mSecurityMessageDisplay.setMessage("", false);
200     }
201 
202     @Override
onKeyDown(int keyCode, KeyEvent event)203     public boolean onKeyDown(int keyCode, KeyEvent event) {
204         onUserInput();
205         return false;
206     }
207 
208     @Override
needsInput()209     public boolean needsInput() {
210         return false;
211     }
212 
213     @Override
onPause()214     public void onPause() {
215         if (mPendingLockCheck != null) {
216             mPendingLockCheck.cancel(false);
217             mPendingLockCheck = null;
218         }
219     }
220 
221     @Override
onResume(int reason)222     public void onResume(int reason) {
223         reset();
224     }
225 
226     @Override
getCallback()227     public KeyguardSecurityCallback getCallback() {
228         return mCallback;
229     }
230 
231     @Override
showPromptReason(int reason)232     public void showPromptReason(int reason) {
233         if (reason != PROMPT_REASON_NONE) {
234             int promtReasonStringRes = getPromtReasonStringRes(reason);
235             if (promtReasonStringRes != 0) {
236                 mSecurityMessageDisplay.setMessage(promtReasonStringRes,
237                         true /* important */);
238             }
239         }
240     }
241 
242     @Override
showMessage(String message, int color)243     public void showMessage(String message, int color) {
244         mSecurityMessageDisplay.setNextMessageColor(color);
245         mSecurityMessageDisplay.setMessage(message, true /* important */);
246     }
247 
getPromtReasonStringRes(int reason)248     protected abstract int getPromtReasonStringRes(int reason);
249 
250     // Cause a VIRTUAL_KEY vibration
doHapticKeyClick()251     public void doHapticKeyClick() {
252         if (mEnableHaptics) {
253             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
254                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
255                     | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
256         }
257     }
258 
259     @Override
startDisappearAnimation(Runnable finishRunnable)260     public boolean startDisappearAnimation(Runnable finishRunnable) {
261         return false;
262     }
263 }
264 
265