OSDN Git Service

Merge "Clear only keystore credential entires" into mnc-dev
[android-x86/packages-apps-Settings.git] / src / com / android / settings / ConfirmLockPassword.java
1 /*
2  * Copyright (C) 2010 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.settings;
18
19 import android.os.UserHandle;
20 import android.text.TextUtils;
21 import com.android.internal.logging.MetricsLogger;
22 import com.android.internal.widget.LockPatternChecker;
23 import com.android.internal.widget.LockPatternUtils;
24 import com.android.internal.widget.TextViewInputDisabler;
25
26 import android.app.Fragment;
27 import android.app.admin.DevicePolicyManager;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.os.AsyncTask;
31 import android.os.Bundle;
32 import android.os.CountDownTimer;
33 import android.os.Handler;
34 import android.os.SystemClock;
35 import android.os.storage.StorageManager;
36 import android.text.InputType;
37 import android.view.KeyEvent;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.view.View.OnClickListener;
41 import android.view.ViewGroup;
42 import android.view.inputmethod.EditorInfo;
43 import android.view.inputmethod.InputMethodManager;
44 import android.widget.TextView;
45 import android.widget.TextView.OnEditorActionListener;
46
47 public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
48
49     public static class InternalActivity extends ConfirmLockPassword {
50     }
51
52     @Override
53     public Intent getIntent() {
54         Intent modIntent = new Intent(super.getIntent());
55         modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockPasswordFragment.class.getName());
56         return modIntent;
57     }
58
59     @Override
60     protected boolean isValidFragment(String fragmentName) {
61         if (ConfirmLockPasswordFragment.class.getName().equals(fragmentName)) return true;
62         return false;
63     }
64
65     @Override
66     public void onWindowFocusChanged(boolean hasFocus) {
67         super.onWindowFocusChanged(hasFocus);
68         Fragment fragment = getFragmentManager().findFragmentById(R.id.main_content);
69         if (fragment != null && fragment instanceof ConfirmLockPasswordFragment) {
70             ((ConfirmLockPasswordFragment)fragment).onWindowFocusChanged(hasFocus);
71         }
72     }
73
74     public static class ConfirmLockPasswordFragment extends ConfirmDeviceCredentialBaseFragment
75             implements OnClickListener, OnEditorActionListener {
76         private static final String KEY_NUM_WRONG_CONFIRM_ATTEMPTS
77                 = "confirm_lock_password_fragment.key_num_wrong_confirm_attempts";
78         private static final long ERROR_MESSAGE_TIMEOUT = 3000;
79         private TextView mPasswordEntry;
80         private TextViewInputDisabler mPasswordEntryInputDisabler;
81         private LockPatternUtils mLockPatternUtils;
82         private AsyncTask<?, ?, ?> mPendingLockCheck;
83         private TextView mHeaderTextView;
84         private TextView mDetailsTextView;
85         private TextView mErrorTextView;
86         private Handler mHandler = new Handler();
87         private int mNumWrongConfirmAttempts;
88         private CountDownTimer mCountdownTimer;
89         private boolean mIsAlpha;
90         private InputMethodManager mImm;
91         private boolean mUsingFingerprint = false;
92
93         // required constructor for fragments
94         public ConfirmLockPasswordFragment() {
95
96         }
97
98         @Override
99         public void onCreate(Bundle savedInstanceState) {
100             super.onCreate(savedInstanceState);
101             mLockPatternUtils = new LockPatternUtils(getActivity());
102             if (savedInstanceState != null) {
103                 mNumWrongConfirmAttempts = savedInstanceState.getInt(
104                         KEY_NUM_WRONG_CONFIRM_ATTEMPTS, 0);
105             }
106         }
107
108         @Override
109         public View onCreateView(LayoutInflater inflater, ViewGroup container,
110                 Bundle savedInstanceState) {
111             final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality(
112                     UserHandle.myUserId());
113             View view = inflater.inflate(R.layout.confirm_lock_password, null);
114
115             mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
116             mPasswordEntry.setOnEditorActionListener(this);
117             mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
118
119             mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
120             mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
121             mErrorTextView = (TextView) view.findViewById(R.id.errorText);
122             mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
123                     || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
124                     || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality;
125
126             mImm = (InputMethodManager) getActivity().getSystemService(
127                     Context.INPUT_METHOD_SERVICE);
128
129             Intent intent = getActivity().getIntent();
130             if (intent != null) {
131                 CharSequence headerMessage = intent.getCharSequenceExtra(
132                         ConfirmDeviceCredentialBaseFragment.HEADER_TEXT);
133                 CharSequence detailsMessage = intent.getCharSequenceExtra(
134                         ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
135                 if (TextUtils.isEmpty(headerMessage)) {
136                     headerMessage = getString(getDefaultHeader());
137                 }
138                 if (TextUtils.isEmpty(detailsMessage)) {
139                     detailsMessage = getString(getDefaultDetails());
140                 }
141                 mHeaderTextView.setText(headerMessage);
142                 mDetailsTextView.setText(detailsMessage);
143             }
144             int currentType = mPasswordEntry.getInputType();
145             mPasswordEntry.setInputType(mIsAlpha ? currentType
146                     : (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
147             return view;
148         }
149
150         private int getDefaultHeader() {
151             return mIsAlpha ? R.string.lockpassword_confirm_your_password_header
152                     : R.string.lockpassword_confirm_your_pin_header;
153         }
154
155         private int getDefaultDetails() {
156             return mIsAlpha ? R.string.lockpassword_confirm_your_password_generic
157                     : R.string.lockpassword_confirm_your_pin_generic;
158         }
159
160         private int getErrorMessage() {
161             return mIsAlpha ? R.string.lockpassword_invalid_password
162                     : R.string.lockpassword_invalid_pin;
163         }
164
165         @Override
166         public void onPause() {
167             super.onPause();
168             if (mCountdownTimer != null) {
169                 mCountdownTimer.cancel();
170                 mCountdownTimer = null;
171             }
172             if (mPendingLockCheck != null) {
173                 mPendingLockCheck.cancel(false);
174                 mPendingLockCheck = null;
175             }
176         }
177
178         @Override
179         protected int getMetricsCategory() {
180             return MetricsLogger.CONFIRM_LOCK_PASSWORD;
181         }
182
183         @Override
184         public void onResume() {
185             super.onResume();
186             long deadline = mLockPatternUtils.getLockoutAttemptDeadline(UserHandle.myUserId());
187             if (deadline != 0) {
188                 handleAttemptLockout(deadline);
189             } else {
190                 resetState();
191             }
192         }
193
194         @Override
195         public void onSaveInstanceState(Bundle outState) {
196             super.onSaveInstanceState(outState);
197             outState.putInt(KEY_NUM_WRONG_CONFIRM_ATTEMPTS, mNumWrongConfirmAttempts);
198         }
199
200         @Override
201         protected void authenticationSucceeded() {
202             Intent intent = new Intent();
203             getActivity().setResult(RESULT_OK, intent);
204             getActivity().finish();
205         }
206
207         @Override
208         public void onFingerprintIconVisibilityChanged(boolean visible) {
209             mUsingFingerprint = visible;
210         }
211
212         private void resetState() {
213             mPasswordEntry.setEnabled(true);
214             mPasswordEntryInputDisabler.setInputEnabled(true);
215             if (shouldAutoShowSoftKeyboard()) {
216                 mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
217             }
218         }
219
220         private boolean shouldAutoShowSoftKeyboard() {
221             return mPasswordEntry.isEnabled() && !mUsingFingerprint;
222         }
223
224         public void onWindowFocusChanged(boolean hasFocus) {
225             if (!hasFocus) {
226                 return;
227             }
228             // Post to let window focus logic to finish to allow soft input show/hide properly.
229             mPasswordEntry.post(new Runnable() {
230                 @Override
231                 public void run() {
232                     if (shouldAutoShowSoftKeyboard()) {
233                         resetState();
234                         return;
235                     }
236
237                     mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(),
238                             InputMethodManager.HIDE_IMPLICIT_ONLY);
239                 }
240             });
241         }
242
243         private void handleNext() {
244             mPasswordEntryInputDisabler.setInputEnabled(false);
245             if (mPendingLockCheck != null) {
246                 mPendingLockCheck.cancel(false);
247             }
248
249             final String pin = mPasswordEntry.getText().toString();
250             final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
251                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
252             Intent intent = new Intent();
253             if (verifyChallenge)  {
254                 if (isInternalActivity()) {
255                     startVerifyPassword(pin, intent);
256                     return;
257                 }
258             } else {
259                 startCheckPassword(pin, intent);
260                 return;
261             }
262
263             onPasswordChecked(false, intent, 0);
264         }
265
266         private boolean isInternalActivity() {
267             return getActivity() instanceof ConfirmLockPassword.InternalActivity;
268         }
269
270         private void startVerifyPassword(final String pin, final Intent intent) {
271             long challenge = getActivity().getIntent().getLongExtra(
272                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
273             mPendingLockCheck = LockPatternChecker.verifyPassword(
274                     mLockPatternUtils,
275                     pin,
276                     challenge,
277                     UserHandle.myUserId(),
278                     new LockPatternChecker.OnVerifyCallback() {
279                         @Override
280                         public void onVerified(byte[] token, int timeoutMs) {
281                             mPendingLockCheck = null;
282                             boolean matched = false;
283                             if (token != null) {
284                                 matched = true;
285                                 intent.putExtra(
286                                         ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
287                                         token);
288                             }
289                             onPasswordChecked(matched, intent, timeoutMs);
290                         }
291                     });
292         }
293
294         private void startCheckPassword(final String pin, final Intent intent) {
295             mPendingLockCheck = LockPatternChecker.checkPassword(
296                     mLockPatternUtils,
297                     pin,
298                     UserHandle.myUserId(),
299                     new LockPatternChecker.OnCheckCallback() {
300                         @Override
301                         public void onChecked(boolean matched, int timeoutMs) {
302                             mPendingLockCheck = null;
303                             if (matched && isInternalActivity()) {
304                                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
305                                                 mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
306                                                          : StorageManager.CRYPT_TYPE_PIN);
307                                 intent.putExtra(
308                                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
309                             }
310                             onPasswordChecked(matched, intent, timeoutMs);
311                         }
312                     });
313         }
314
315         private void onPasswordChecked(boolean matched, Intent intent, int timeoutMs) {
316             mPasswordEntryInputDisabler.setInputEnabled(true);
317             if (matched) {
318                 getActivity().setResult(RESULT_OK, intent);
319                 getActivity().finish();
320             } else {
321                 if (timeoutMs > 0) {
322                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
323                             UserHandle.myUserId(), timeoutMs);
324                     handleAttemptLockout(deadline);
325                 } else {
326                     showError(getErrorMessage());
327                 }
328             }
329         }
330
331         private void handleAttemptLockout(long elapsedRealtimeDeadline) {
332             long elapsedRealtime = SystemClock.elapsedRealtime();
333             mPasswordEntry.setEnabled(false);
334             mCountdownTimer = new CountDownTimer(
335                     elapsedRealtimeDeadline - elapsedRealtime,
336                     LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
337
338                 @Override
339                 public void onTick(long millisUntilFinished) {
340                     final int secondsCountdown = (int) (millisUntilFinished / 1000);
341                     showError(getString(
342                             R.string.lockpattern_too_many_failed_confirmation_attempts,
343                             secondsCountdown), 0);
344                 }
345
346                 @Override
347                 public void onFinish() {
348                     resetState();
349                     mErrorTextView.setText("");
350                     mNumWrongConfirmAttempts = 0;
351                 }
352             }.start();
353         }
354
355         public void onClick(View v) {
356             switch (v.getId()) {
357                 case R.id.next_button:
358                     handleNext();
359                     break;
360
361                 case R.id.cancel_button:
362                     getActivity().setResult(RESULT_CANCELED);
363                     getActivity().finish();
364                     break;
365             }
366         }
367
368         private void showError(int msg) {
369             showError(msg, ERROR_MESSAGE_TIMEOUT);
370         }
371
372         private final Runnable mResetErrorRunnable = new Runnable() {
373             public void run() {
374                 mErrorTextView.setText("");
375             }
376         };
377
378         private void showError(CharSequence msg, long timeout) {
379             mErrorTextView.setText(msg);
380             mErrorTextView.announceForAccessibility(mErrorTextView.getText());
381             mPasswordEntry.setText(null);
382             mHandler.removeCallbacks(mResetErrorRunnable);
383             if (timeout != 0) {
384                 mHandler.postDelayed(mResetErrorRunnable, timeout);
385             }
386         }
387
388         private void showError(int msg, long timeout) {
389             showError(getText(msg), timeout);
390         }
391
392         // {@link OnEditorActionListener} methods.
393         public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
394             // Check if this was the result of hitting the enter or "done" key
395             if (actionId == EditorInfo.IME_NULL
396                     || actionId == EditorInfo.IME_ACTION_DONE
397                     || actionId == EditorInfo.IME_ACTION_NEXT) {
398                 handleNext();
399                 return true;
400             }
401             return false;
402         }
403     }
404 }