ChooseLockPassword.java revision 57fbf694a53afb9c1924d81272179dceb3acfa4d
100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller/*
200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * Copyright (C) 2010 The Android Open Source Project
300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller *
400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * Licensed under the Apache License, Version 2.0 (the "License");
500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * you may not use this file except in compliance with the License.
600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * You may obtain a copy of the License at
700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller *
800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller *      http://www.apache.org/licenses/LICENSE-2.0
900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller *
1000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * Unless required by applicable law or agreed to in writing, software
1100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * distributed under the License is distributed on an "AS IS" BASIS,
1200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * See the License for the specific language governing permissions and
1400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller * limitations under the License.
1500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller */
1600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
1700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerpackage com.android.settings;
1800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
1900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport com.android.internal.widget.LockPatternUtils;
202f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Millerimport com.android.internal.widget.PasswordEntryKeyboardHelper;
212f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Millerimport com.android.internal.widget.PasswordEntryKeyboardView;
2200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
2300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.app.Activity;
24af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Millerimport android.app.admin.DevicePolicyManager;
2500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.content.Intent;
262f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Millerimport android.inputmethodservice.KeyboardView;
2700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.os.Bundle;
2800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.os.Handler;
2900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.text.Editable;
30122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerimport android.text.Selection;
31122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerimport android.text.Spannable;
3200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.text.TextUtils;
33122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerimport android.text.TextWatcher;
34122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerimport android.view.KeyEvent;
3500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.view.View;
362f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Millerimport android.view.WindowManager;
3700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.view.View.OnClickListener;
38122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerimport android.view.inputmethod.EditorInfo;
3900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.widget.Button;
4000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Millerimport android.widget.TextView;
41122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerimport android.widget.TextView.OnEditorActionListener;
4200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
4300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
44122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Millerpublic class ChooseLockPassword extends Activity implements OnClickListener, OnEditorActionListener,
45122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        TextWatcher {
46122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private static final String KEY_FIRST_PIN = "first_pin";
47122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private static final String KEY_UI_STAGE = "ui_stage";
482f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    private TextView mPasswordEntry;
4900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private int mPasswordMinLength = 4;
5070d5c3a0139899e5f4d425c8ab2d68f0dfc5c6daJim Miller    private int mPasswordMaxLength = 16;
5157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    private int mPasswordMinLetters = 0;
5257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    private int mPasswordMinUpperCase = 0;
5357fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    private int mPasswordMinLowerCase = 0;
5457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    private int mPasswordMinSymbols = 0;
5557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    private int mPasswordMinNumeric = 0;
5600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private LockPatternUtils mLockPatternUtils;
57af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller    private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
5800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private ChooseLockSettingsHelper mChooseLockSettingsHelper;
5900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private com.android.settings.ChooseLockPassword.Stage mUiStage = Stage.Introduction;
6000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private TextView mHeaderText;
6100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private String mFirstPin;
622f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    private KeyboardView mKeyboardView;
632f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    private PasswordEntryKeyboardHelper mKeyboardHelper;
64122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private boolean mIsAlphaMode;
65122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private Button mCancelButton;
66122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private Button mNextButton;
6700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
6800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
6957fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    public static final String PASSWORD_MIN_LETTERS_KEY = "lockscreen.password_min_letters";
7057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    public static final String PASSWORD_MIN_LOWERCASE_KEY = "lockscreen.password_min_lowercase";
7157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    public static final String PASSWORD_MIN_UPPERCASE_KEY = "lockscreen.password_min_uppercase";
7257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    public static final String PASSWORD_MIN_NUMERIC_KEY = "lockscreen.password_min_numeric";
7357fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev    public static final String PASSWORD_MIN_SYMBOLS_KEY = "lockscreen.password_min_symbols";
7400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private static Handler mHandler = new Handler();
7500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private static final int CONFIRM_EXISTING_REQUEST = 58;
7600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    static final int RESULT_FINISHED = RESULT_FIRST_USER;
7700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private static final long ERROR_MESSAGE_TIMEOUT = 3000;
7800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
7900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    /**
8000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     * Keep track internally of where the user is in choosing a pattern.
8100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     */
8200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected enum Stage {
8300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
84122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        Introduction(R.string.lockpassword_choose_your_password_header,
85122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_choose_your_pin_header,
86122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_continue_label),
87122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
88122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        NeedToConfirm(R.string.lockpassword_confirm_your_password_header,
89122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_confirm_your_pin_header,
90122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_ok_label),
91122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
92122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match,
93122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_confirm_pins_dont_match,
94122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_continue_label);
9500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
9600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        /**
9700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller         * @param headerMessage The message displayed at the top.
9800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller         */
99122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) {
100122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            this.alphaHint = hintInAlpha;
101122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            this.numericHint = hintInNumeric;
102122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            this.buttonText = nextButtonText;
10300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
10400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
105122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        public final int alphaHint;
106122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        public final int numericHint;
107122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        public final int buttonText;
10800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
10900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
11000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    @Override
11100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void onCreate(Bundle savedInstanceState) {
11200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        super.onCreate(savedInstanceState);
11347d380f1e6c823cea444004cb799d4c791145cc6Jim Miller        mLockPatternUtils = new LockPatternUtils(this);
11457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mRequestedQuality = Math.max(getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
11557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                mRequestedQuality), mLockPatternUtils.getRequestedPasswordQuality());
11657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mPasswordMinLength = Math.max(
11757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                getIntent().getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength), mLockPatternUtils
11857fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        .getRequestedMinimumPasswordLength());
11970d5c3a0139899e5f4d425c8ab2d68f0dfc5c6daJim Miller        mPasswordMaxLength = getIntent().getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
12057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mPasswordMinLetters = Math.max(getIntent().getIntExtra(PASSWORD_MIN_LETTERS_KEY,
12157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                mPasswordMinLetters), mLockPatternUtils.getRequestedPasswordMinimumLetters());
12257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mPasswordMinUpperCase = Math.max(getIntent().getIntExtra(PASSWORD_MIN_UPPERCASE_KEY,
12357fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                mPasswordMinUpperCase), mLockPatternUtils.getRequestedPasswordMinimumUpperCase());
12457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mPasswordMinLowerCase = Math.max(getIntent().getIntExtra(PASSWORD_MIN_LOWERCASE_KEY,
12557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                mPasswordMinLowerCase), mLockPatternUtils.getRequestedPasswordMinimumLowerCase());
12657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mPasswordMinNumeric = Math.max(getIntent().getIntExtra(PASSWORD_MIN_NUMERIC_KEY,
12757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                mPasswordMinNumeric), mLockPatternUtils.getRequestedPasswordMinimumNumeric());
12857fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        mPasswordMinSymbols = Math.max(getIntent().getIntExtra(PASSWORD_MIN_SYMBOLS_KEY,
12957fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                mPasswordMinSymbols), mLockPatternUtils.getRequestedPasswordMinimumSymbols());
130bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller        final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
13157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev
13257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev
13300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        initViews();
13400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
13500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        if (savedInstanceState == null) {
13600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            updateStage(Stage.Introduction);
137bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller            if (confirmCredentials) {
1382deec7edc937b1d19df0a74c4cd0c5ee3ef33070Jim Miller                mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
1392deec7edc937b1d19df0a74c4cd0c5ee3ef33070Jim Miller                        null, null);
140bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller            }
14100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
14200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
14300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
14400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private void initViews() {
1452f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        setContentView(R.layout.choose_lock_password);
1462f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        // Disable IME on our window since we provide our own keyboard
1472f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
1482f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1492f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
150122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mCancelButton = (Button) findViewById(R.id.cancel_button);
151122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mCancelButton.setOnClickListener(this);
152122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton = (Button) findViewById(R.id.next_button);
153122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton.setOnClickListener(this);
1542f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
1552f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
1562f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mPasswordEntry = (TextView) findViewById(R.id.password_entry);
157122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mPasswordEntry.setOnEditorActionListener(this);
158122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mPasswordEntry.addTextChangedListener(this);
1592f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
160af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
16157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality
16257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality;
1632f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
164122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
165122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
1662f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller                : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
1672f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
16800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHeaderText = (TextView) findViewById(R.id.headerText);
1692f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView.requestFocus();
1702f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    }
1712f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
1722f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    @Override
1732f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    protected void onResume() {
1742f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        super.onResume();
1752f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        updateStage(mUiStage);
1762f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView.requestFocus();
17700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
17800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
17900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    @Override
180122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    protected void onSaveInstanceState(Bundle outState) {
181122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        super.onSaveInstanceState(outState);
182122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        outState.putString(KEY_UI_STAGE, mUiStage.name());
183122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        outState.putString(KEY_FIRST_PIN, mFirstPin);
184122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
185122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
186122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    @Override
187122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    protected void onRestoreInstanceState(Bundle savedInstanceState) {
188122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        super.onRestoreInstanceState(savedInstanceState);
189122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        String state = savedInstanceState.getString(KEY_UI_STAGE);
190122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
191122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (state != null) {
192122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mUiStage = Stage.valueOf(state);
193122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            updateStage(mUiStage);
194122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
195122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
196122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
197122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    @Override
19800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void onActivityResult(int requestCode, int resultCode,
19900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            Intent data) {
20000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        super.onActivityResult(requestCode, resultCode, data);
20100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        switch (requestCode) {
20200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            case CONFIRM_EXISTING_REQUEST:
20300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                if (resultCode != Activity.RESULT_OK) {
20400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                    setResult(RESULT_FINISHED);
20500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                    finish();
20600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                }
20700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
20800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
20900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
21000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
21100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void updateStage(Stage stage) {
21200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mUiStage = stage;
213122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        updateUi();
21400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
21500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
21600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    /**
21700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     * Validates PIN and returns a message to display if PIN fails test.
218af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller     * @param password the raw password the user typed in
219af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller     * @return error message to show to user or null if password is OK
22000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     */
221af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller    private String validatePassword(String password) {
222af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (password.length() < mPasswordMinLength) {
223122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return getString(mIsAlphaMode ?
224122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    R.string.lockpassword_password_too_short
225122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    : R.string.lockpassword_pin_too_short, mPasswordMinLength);
22600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
227af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (password.length() > mPasswordMaxLength) {
228122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return getString(mIsAlphaMode ?
229122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    R.string.lockpassword_password_too_long
230122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    : R.string.lockpassword_pin_too_long, mPasswordMaxLength);
23100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
23257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        int letters = 0;
23357fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        int numbers = 0;
23457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        int lowercase = 0;
23557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        int symbols = 0;
23657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        int uppercase = 0;
237af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        for (int i = 0; i < password.length(); i++) {
238af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            char c = password.charAt(i);
239122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            // allow non white space Latin-1 characters only
240122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (c <= 32 || c > 127) {
241122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                return getString(R.string.lockpassword_illegal_character);
24200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
243122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (c >= '0' && c <= '9') {
24457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                numbers++;
24557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            } else if (c >= 'A' && c <= 'Z') {
24657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                letters++;
24757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                uppercase++;
24857fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            } else if (c >= 'a' && c <= 'z') {
24957fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                letters++;
25057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                lowercase++;
251122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
25257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                symbols++;
25300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
25400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
255af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
25657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                && (letters > 0 || symbols > 0)) {
25757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            // This shouldn't be possible unless user finds some way to bring up
25857fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            // soft keyboard
259af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            return getString(R.string.lockpassword_pin_contains_non_digits);
26057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev        } else if (DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality) {
26157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            if (letters < mPasswordMinLetters) {
26257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                return String.format(getResources().getQuantityString(
26357fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters),
26457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        mPasswordMinLetters);
26557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            } else if (numbers < mPasswordMinNumeric) {
26657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                return String.format(getResources().getQuantityString(
26757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric),
26857fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        mPasswordMinNumeric);
26957fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            } else if (lowercase < mPasswordMinLowerCase) {
27057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                return String.format(getResources().getQuantityString(
27157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase),
27257fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        mPasswordMinLowerCase);
27357fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            } else if (uppercase < mPasswordMinUpperCase) {
27457fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                return String.format(getResources().getQuantityString(
27557fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase),
27657fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        mPasswordMinUpperCase);
27757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            } else if (symbols < mPasswordMinSymbols) {
27857fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                return String.format(getResources().getQuantityString(
27957fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols),
28057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev                        mPasswordMinSymbols);
28157fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            }
282af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        } else {
283af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
284af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    == mRequestedQuality;
285af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
286af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    == mRequestedQuality;
28757fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            if ((alphabetic || alphanumeric) && letters == 0) {
288af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_alpha);
289af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
29057fbf694a53afb9c1924d81272179dceb3acfa4dKonstantin Lopyrev            if (alphanumeric && numbers == 0) {
291af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_digit);
292af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
293122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
294015c186a2466ad1bee01952ef067ba8d7e21cab7Konstantin Lopyrev        if(mLockPatternUtils.checkPasswordHistory(password)) {
295015c186a2466ad1bee01952ef067ba8d7e21cab7Konstantin Lopyrev            return getString(mIsAlphaMode ? R.string.lockpassword_password_recently_used
296015c186a2466ad1bee01952ef067ba8d7e21cab7Konstantin Lopyrev                    : R.string.lockpassword_pin_recently_used);
297015c186a2466ad1bee01952ef067ba8d7e21cab7Konstantin Lopyrev        }
29800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        return null;
29900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
30000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
301122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private void handleNext() {
302122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        final String pin = mPasswordEntry.getText().toString();
303122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (TextUtils.isEmpty(pin)) {
304122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return;
305122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
306122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        String errorMsg = null;
307122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.Introduction) {
308122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            errorMsg = validatePassword(pin);
309122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (errorMsg == null) {
310122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mFirstPin = pin;
311122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                updateStage(Stage.NeedToConfirm);
312122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mPasswordEntry.setText("");
313122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
314122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        } else if (mUiStage == Stage.NeedToConfirm) {
315122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (mFirstPin.equals(pin)) {
316122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mLockPatternUtils.clearLock();
317af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
318122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                finish();
319122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
320122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                updateStage(Stage.ConfirmWrong);
321122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                CharSequence tmp = mPasswordEntry.getText();
322122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                if (tmp != null) {
323122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    Selection.setSelection((Spannable) tmp, 0, tmp.length());
324122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                }
325122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
326122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
327122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (errorMsg != null) {
328122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            showError(errorMsg, mUiStage);
329122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
330122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
331122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
33200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public void onClick(View v) {
33300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        switch (v.getId()) {
3342f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller            case R.id.next_button:
335122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                handleNext();
33600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
33700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
3382f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller            case R.id.cancel_button:
33900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                finish();
34000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
34100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
34200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
34300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
34400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private void showError(String msg, final Stage next) {
34500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHeaderText.setText(msg);
34600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHandler.postDelayed(new Runnable() {
34700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            public void run() {
34800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                updateStage(next);
34900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
35000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }, ERROR_MESSAGE_TIMEOUT);
35100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
352122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
353122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
354122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        // Check if this was the result of hitting the enter key
355015c186a2466ad1bee01952ef067ba8d7e21cab7Konstantin Lopyrev        if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN) {
356122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            handleNext();
357122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return true;
358122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
359122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        return false;
360122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
361122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
362122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    /**
363122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller     * Update the hint based on current Stage and length of password entry
364122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller     */
365122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private void updateUi() {
366af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        String password = mPasswordEntry.getText().toString();
367af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        final int length = password.length();
368122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.Introduction && length > 0) {
369122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (length < mPasswordMinLength) {
370122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
371122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                        : R.string.lockpassword_pin_too_short, mPasswordMinLength);
372122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mHeaderText.setText(msg);
373122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mNextButton.setEnabled(false);
374122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
375af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                String error = validatePassword(password);
376af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                if (error != null) {
377af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mHeaderText.setText(error);
378af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mNextButton.setEnabled(false);
379af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                } else {
380af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mHeaderText.setText(R.string.lockpassword_press_continue);
381af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mNextButton.setEnabled(true);
382af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                }
383122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
384122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        } else {
385122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
386122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mNextButton.setEnabled(length > 0);
387122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
388122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton.setText(mUiStage.buttonText);
389122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
390122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
391122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void afterTextChanged(Editable s) {
392122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        // Changing the text while error displayed resets to NeedToConfirm state
393122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.ConfirmWrong) {
394122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mUiStage = Stage.NeedToConfirm;
395122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
396122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        updateUi();
397122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
398122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
399122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
400122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
401122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
402122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
403122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void onTextChanged(CharSequence s, int start, int before, int count) {
404122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
405122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
40600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller}
407