OSDN Git Service

Clear only keystore credential entires
[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
92         // required constructor for fragments
93         public ConfirmLockPasswordFragment() {
94
95         }
96
97         @Override
98         public void onCreate(Bundle savedInstanceState) {
99             super.onCreate(savedInstanceState);
100             mLockPatternUtils = new LockPatternUtils(getActivity());
101             if (savedInstanceState != null) {
102                 mNumWrongConfirmAttempts = savedInstanceState.getInt(
103                         KEY_NUM_WRONG_CONFIRM_ATTEMPTS, 0);
104             }
105         }
106
107         @Override
108         public View onCreateView(LayoutInflater inflater, ViewGroup container,
109                 Bundle savedInstanceState) {
110             final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality(
111                     UserHandle.myUserId());
112             View view = inflater.inflate(R.layout.confirm_lock_password, null);
113
114             mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
115             mPasswordEntry.setOnEditorActionListener(this);
116             mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
117
118             mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
119             mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
120             mErrorTextView = (TextView) view.findViewById(R.id.errorText);
121             mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
122                     || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
123                     || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality;
124
125             mImm = (InputMethodManager) getActivity().getSystemService(
126                     Context.INPUT_METHOD_SERVICE);
127
128             Intent intent = getActivity().getIntent();
129             if (intent != null) {
130                 CharSequence headerMessage = intent.getCharSequenceExtra(
131                         ConfirmDeviceCredentialBaseFragment.HEADER_TEXT);
132                 CharSequence detailsMessage = intent.getCharSequenceExtra(
133                         ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
134                 if (TextUtils.isEmpty(headerMessage)) {
135                     headerMessage = getString(getDefaultHeader());
136                 }
137                 if (TextUtils.isEmpty(detailsMessage)) {
138                     detailsMessage = getString(getDefaultDetails());
139                 }
140                 mHeaderTextView.setText(headerMessage);
141                 mDetailsTextView.setText(detailsMessage);
142             }
143             int currentType = mPasswordEntry.getInputType();
144             mPasswordEntry.setInputType(mIsAlpha ? currentType
145                     : (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
146             return view;
147         }
148
149         private int getDefaultHeader() {
150             return mIsAlpha ? R.string.lockpassword_confirm_your_password_header
151                     : R.string.lockpassword_confirm_your_pin_header;
152         }
153
154         private int getDefaultDetails() {
155             return mIsAlpha ? R.string.lockpassword_confirm_your_password_generic
156                     : R.string.lockpassword_confirm_your_pin_generic;
157         }
158
159         private int getErrorMessage() {
160             return mIsAlpha ? R.string.lockpassword_invalid_password
161                     : R.string.lockpassword_invalid_pin;
162         }
163
164         @Override
165         public void onPause() {
166             super.onPause();
167             if (mCountdownTimer != null) {
168                 mCountdownTimer.cancel();
169                 mCountdownTimer = null;
170             }
171             if (mPendingLockCheck != null) {
172                 mPendingLockCheck.cancel(false);
173                 mPendingLockCheck = null;
174             }
175         }
176
177         @Override
178         protected int getMetricsCategory() {
179             return MetricsLogger.CONFIRM_LOCK_PASSWORD;
180         }
181
182         @Override
183         public void onResume() {
184             super.onResume();
185             long deadline = mLockPatternUtils.getLockoutAttemptDeadline(UserHandle.myUserId());
186             if (deadline != 0) {
187                 handleAttemptLockout(deadline);
188             } else {
189                 resetState();
190             }
191         }
192
193         @Override
194         public void onSaveInstanceState(Bundle outState) {
195             super.onSaveInstanceState(outState);
196             outState.putInt(KEY_NUM_WRONG_CONFIRM_ATTEMPTS, mNumWrongConfirmAttempts);
197         }
198
199         @Override
200         protected void authenticationSucceeded() {
201             Intent intent = new Intent();
202             getActivity().setResult(RESULT_OK, intent);
203             getActivity().finish();
204         }
205
206         private void resetState() {
207             mPasswordEntry.setEnabled(true);
208             mPasswordEntryInputDisabler.setInputEnabled(true);
209             mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
210         }
211
212         public void onWindowFocusChanged(boolean hasFocus) {
213             if (!hasFocus) {
214                 return;
215             }
216             // Post to let window focus logic to finish to allow soft input show/hide properly.
217             mPasswordEntry.post(new Runnable() {
218                 @Override
219                 public void run() {
220                     if (mPasswordEntry.isEnabled()) {
221                         resetState();
222                         return;
223                     }
224
225                     mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(),
226                             InputMethodManager.HIDE_IMPLICIT_ONLY);
227                 }
228             });
229         }
230
231         private void handleNext() {
232             mPasswordEntryInputDisabler.setInputEnabled(false);
233             if (mPendingLockCheck != null) {
234                 mPendingLockCheck.cancel(false);
235             }
236
237             final String pin = mPasswordEntry.getText().toString();
238             final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
239                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
240             Intent intent = new Intent();
241             if (verifyChallenge)  {
242                 if (isInternalActivity()) {
243                     startVerifyPassword(pin, intent);
244                     return;
245                 }
246             } else {
247                 startCheckPassword(pin, intent);
248                 return;
249             }
250
251             onPasswordChecked(false, intent);
252         }
253
254         private boolean isInternalActivity() {
255             return getActivity() instanceof ConfirmLockPassword.InternalActivity;
256         }
257
258         private void startVerifyPassword(final String pin, final Intent intent) {
259             long challenge = getActivity().getIntent().getLongExtra(
260                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
261             mPendingLockCheck = LockPatternChecker.verifyPassword(
262                     mLockPatternUtils,
263                     pin,
264                     challenge,
265                     UserHandle.myUserId(),
266                     new LockPatternChecker.OnVerifyCallback() {
267                         @Override
268                         public void onVerified(byte[] token) {
269                             mPendingLockCheck = null;
270                             boolean matched = false;
271                             if (token != null) {
272                                 matched = true;
273                                 intent.putExtra(
274                                         ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
275                                         token);
276                             }
277                             onPasswordChecked(matched, intent);
278                         }
279                     });
280         }
281
282         private void startCheckPassword(final String pin, final Intent intent) {
283             mPendingLockCheck = LockPatternChecker.checkPassword(
284                     mLockPatternUtils,
285                     pin,
286                     UserHandle.myUserId(),
287                     new LockPatternChecker.OnCheckCallback() {
288                         @Override
289                         public void onChecked(boolean matched) {
290                             mPendingLockCheck = null;
291                             if (matched && isInternalActivity()) {
292                                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
293                                                 mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
294                                                          : StorageManager.CRYPT_TYPE_PIN);
295                                 intent.putExtra(
296                                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
297                             }
298                             onPasswordChecked(matched, intent);
299                         }
300                     });
301         }
302
303         private void onPasswordChecked(boolean matched, Intent intent) {
304             mPasswordEntryInputDisabler.setInputEnabled(true);
305             if (matched) {
306                 getActivity().setResult(RESULT_OK, intent);
307                 getActivity().finish();
308             } else {
309                 if (++mNumWrongConfirmAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
310                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
311                             UserHandle.myUserId());
312                     handleAttemptLockout(deadline);
313                 } else {
314                     showError(getErrorMessage());
315                 }
316             }
317         }
318
319         private void handleAttemptLockout(long elapsedRealtimeDeadline) {
320             long elapsedRealtime = SystemClock.elapsedRealtime();
321             mPasswordEntry.setEnabled(false);
322             mCountdownTimer = new CountDownTimer(
323                     elapsedRealtimeDeadline - elapsedRealtime,
324                     LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
325
326                 @Override
327                 public void onTick(long millisUntilFinished) {
328                     final int secondsCountdown = (int) (millisUntilFinished / 1000);
329                     showError(getString(
330                             R.string.lockpattern_too_many_failed_confirmation_attempts,
331                             secondsCountdown), 0);
332                 }
333
334                 @Override
335                 public void onFinish() {
336                     resetState();
337                     mErrorTextView.setText("");
338                     mNumWrongConfirmAttempts = 0;
339                 }
340             }.start();
341         }
342
343         public void onClick(View v) {
344             switch (v.getId()) {
345                 case R.id.next_button:
346                     handleNext();
347                     break;
348
349                 case R.id.cancel_button:
350                     getActivity().setResult(RESULT_CANCELED);
351                     getActivity().finish();
352                     break;
353             }
354         }
355
356         private void showError(int msg) {
357             showError(msg, ERROR_MESSAGE_TIMEOUT);
358         }
359
360         private final Runnable mResetErrorRunnable = new Runnable() {
361             public void run() {
362                 mErrorTextView.setText("");
363             }
364         };
365
366         private void showError(CharSequence msg, long timeout) {
367             mErrorTextView.setText(msg);
368             mErrorTextView.announceForAccessibility(mErrorTextView.getText());
369             mPasswordEntry.setText(null);
370             mHandler.removeCallbacks(mResetErrorRunnable);
371             if (timeout != 0) {
372                 mHandler.postDelayed(mResetErrorRunnable, timeout);
373             }
374         }
375
376         private void showError(int msg, long timeout) {
377             showError(getText(msg), timeout);
378         }
379
380         // {@link OnEditorActionListener} methods.
381         public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
382             // Check if this was the result of hitting the enter or "done" key
383             if (actionId == EditorInfo.IME_NULL
384                     || actionId == EditorInfo.IME_ACTION_DONE
385                     || actionId == EditorInfo.IME_ACTION_NEXT) {
386                 handleNext();
387                 return true;
388             }
389             return false;
390         }
391     }
392 }