ConfirmLockPattern and ConfirmLockPassword return an intent that contains the password, and as such are dangerous. Create internal versions that are locked down, and don't put this info in the externally accessible versions. Bug: 13741939 Change-Id: I0df4d1e720b3c33d2c9ca086636dc54f17b19bf0
275 lines
11 KiB
Java
275 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings;
|
|
|
|
import com.android.internal.widget.LockPatternUtils;
|
|
import com.android.internal.widget.PasswordEntryKeyboardHelper;
|
|
import com.android.internal.widget.PasswordEntryKeyboardView;
|
|
|
|
import android.app.Activity;
|
|
import android.app.Fragment;
|
|
import android.app.admin.DevicePolicyManager;
|
|
import android.content.Intent;
|
|
import android.os.Bundle;
|
|
import android.os.CountDownTimer;
|
|
import android.os.Handler;
|
|
import android.os.SystemClock;
|
|
import android.os.storage.StorageManager;
|
|
import android.text.Editable;
|
|
import android.text.InputType;
|
|
import android.text.TextWatcher;
|
|
import android.view.KeyEvent;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.View.OnClickListener;
|
|
import android.view.ViewGroup;
|
|
import android.view.inputmethod.EditorInfo;
|
|
import android.widget.Button;
|
|
import android.widget.TextView;
|
|
import android.widget.TextView.OnEditorActionListener;
|
|
|
|
public class ConfirmLockPassword extends SettingsActivity {
|
|
|
|
public static class InternalActivity extends ConfirmLockPassword {
|
|
}
|
|
|
|
@Override
|
|
public Intent getIntent() {
|
|
Intent modIntent = new Intent(super.getIntent());
|
|
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockPasswordFragment.class.getName());
|
|
return modIntent;
|
|
}
|
|
|
|
@Override
|
|
protected boolean isValidFragment(String fragmentName) {
|
|
if (ConfirmLockPasswordFragment.class.getName().equals(fragmentName)) return true;
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
// Disable IME on our window since we provide our own keyboard
|
|
//getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
|
|
//WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
|
super.onCreate(savedInstanceState);
|
|
CharSequence msg = getText(R.string.lockpassword_confirm_your_password_header);
|
|
setTitle(msg);
|
|
}
|
|
|
|
public static class ConfirmLockPasswordFragment extends Fragment implements OnClickListener,
|
|
OnEditorActionListener, TextWatcher {
|
|
private static final long ERROR_MESSAGE_TIMEOUT = 3000;
|
|
private TextView mPasswordEntry;
|
|
private LockPatternUtils mLockPatternUtils;
|
|
private TextView mHeaderText;
|
|
private Handler mHandler = new Handler();
|
|
private PasswordEntryKeyboardHelper mKeyboardHelper;
|
|
private PasswordEntryKeyboardView mKeyboardView;
|
|
private Button mContinueButton;
|
|
private int mNumWrongConfirmAttempts;
|
|
private CountDownTimer mCountdownTimer;
|
|
private boolean mIsAlpha;
|
|
|
|
// required constructor for fragments
|
|
public ConfirmLockPasswordFragment() {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
mLockPatternUtils = new LockPatternUtils(getActivity());
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
Bundle savedInstanceState) {
|
|
final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
|
|
View view = inflater.inflate(R.layout.confirm_lock_password, null);
|
|
// Disable IME on our window since we provide our own keyboard
|
|
|
|
view.findViewById(R.id.cancel_button).setOnClickListener(this);
|
|
mContinueButton = (Button) view.findViewById(R.id.next_button);
|
|
mContinueButton.setOnClickListener(this);
|
|
mContinueButton.setEnabled(false); // disable until the user enters at least one char
|
|
|
|
mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
|
|
mPasswordEntry.setOnEditorActionListener(this);
|
|
mPasswordEntry.addTextChangedListener(this);
|
|
|
|
mKeyboardView = (PasswordEntryKeyboardView) view.findViewById(R.id.keyboard);
|
|
mHeaderText = (TextView) view.findViewById(R.id.headerText);
|
|
mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|
|
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
|
|
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality;
|
|
mHeaderText.setText(getDefaultHeader());
|
|
|
|
final Activity activity = getActivity();
|
|
mKeyboardHelper = new PasswordEntryKeyboardHelper(activity,
|
|
mKeyboardView, mPasswordEntry);
|
|
mKeyboardHelper.setKeyboardMode(mIsAlpha ?
|
|
PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
|
|
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
|
|
mKeyboardView.requestFocus();
|
|
|
|
int currentType = mPasswordEntry.getInputType();
|
|
mPasswordEntry.setInputType(mIsAlpha ? currentType
|
|
: (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
|
|
|
|
if (activity instanceof SettingsActivity) {
|
|
final SettingsActivity sa = (SettingsActivity) activity;
|
|
int id = getDefaultHeader();
|
|
CharSequence title = getText(id);
|
|
sa.setTitle(title);
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
private int getDefaultHeader() {
|
|
return mIsAlpha ? R.string.lockpassword_confirm_your_password_header
|
|
: R.string.lockpassword_confirm_your_pin_header;
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
mKeyboardView.requestFocus();
|
|
if (mCountdownTimer != null) {
|
|
mCountdownTimer.cancel();
|
|
mCountdownTimer = null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
// TODO Auto-generated method stub
|
|
super.onResume();
|
|
mKeyboardView.requestFocus();
|
|
long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
|
|
if (deadline != 0) {
|
|
handleAttemptLockout(deadline);
|
|
}
|
|
}
|
|
|
|
private void handleNext() {
|
|
final String pin = mPasswordEntry.getText().toString();
|
|
if (mLockPatternUtils.checkPassword(pin)) {
|
|
|
|
Intent intent = new Intent();
|
|
if (getActivity() instanceof ConfirmLockPassword.InternalActivity) {
|
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
|
|
mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
|
|
: StorageManager.CRYPT_TYPE_PIN);
|
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
|
|
}
|
|
|
|
getActivity().setResult(RESULT_OK, intent);
|
|
getActivity().finish();
|
|
} else {
|
|
if (++mNumWrongConfirmAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
|
|
long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
|
|
handleAttemptLockout(deadline);
|
|
} else {
|
|
showError(R.string.lockpattern_need_to_unlock_wrong);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
|
|
long elapsedRealtime = SystemClock.elapsedRealtime();
|
|
showError(R.string.lockpattern_too_many_failed_confirmation_attempts_header, 0);
|
|
mPasswordEntry.setEnabled(false);
|
|
mCountdownTimer = new CountDownTimer(
|
|
elapsedRealtimeDeadline - elapsedRealtime,
|
|
LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
|
|
|
|
@Override
|
|
public void onTick(long millisUntilFinished) {
|
|
final int secondsCountdown = (int) (millisUntilFinished / 1000);
|
|
mHeaderText.setText(getString(
|
|
R.string.lockpattern_too_many_failed_confirmation_attempts_footer,
|
|
secondsCountdown));
|
|
}
|
|
|
|
@Override
|
|
public void onFinish() {
|
|
mPasswordEntry.setEnabled(true);
|
|
mHeaderText.setText(getDefaultHeader());
|
|
mNumWrongConfirmAttempts = 0;
|
|
}
|
|
}.start();
|
|
}
|
|
|
|
public void onClick(View v) {
|
|
switch (v.getId()) {
|
|
case R.id.next_button:
|
|
handleNext();
|
|
break;
|
|
|
|
case R.id.cancel_button:
|
|
getActivity().setResult(RESULT_CANCELED);
|
|
getActivity().finish();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void showError(int msg) {
|
|
showError(msg, ERROR_MESSAGE_TIMEOUT);
|
|
}
|
|
|
|
private final Runnable mResetErrorRunnable = new Runnable() {
|
|
public void run() {
|
|
mHeaderText.setText(getDefaultHeader());
|
|
}
|
|
};
|
|
|
|
private void showError(int msg, long timeout) {
|
|
mHeaderText.setText(msg);
|
|
mHeaderText.announceForAccessibility(mHeaderText.getText());
|
|
mPasswordEntry.setText(null);
|
|
mHandler.removeCallbacks(mResetErrorRunnable);
|
|
if (timeout != 0) {
|
|
mHandler.postDelayed(mResetErrorRunnable, timeout);
|
|
}
|
|
}
|
|
|
|
// {@link OnEditorActionListener} methods.
|
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
|
// Check if this was the result of hitting the enter or "done" key
|
|
if (actionId == EditorInfo.IME_NULL
|
|
|| actionId == EditorInfo.IME_ACTION_DONE
|
|
|| actionId == EditorInfo.IME_ACTION_NEXT) {
|
|
handleNext();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// {@link TextWatcher} methods.
|
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
}
|
|
|
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
}
|
|
|
|
public void afterTextChanged(Editable s) {
|
|
mContinueButton.setEnabled(mPasswordEntry.getText().length() > 0);
|
|
}
|
|
}
|
|
}
|