ChooseLockPassword.java revision af366a3ed66dcb3c3ecb1dd101e5d8869b518598
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;
5100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private LockPatternUtils mLockPatternUtils;
52af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller    private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
5300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private ChooseLockSettingsHelper mChooseLockSettingsHelper;
5400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private com.android.settings.ChooseLockPassword.Stage mUiStage = Stage.Introduction;
5500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private TextView mHeaderText;
5600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private String mFirstPin;
572f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    private KeyboardView mKeyboardView;
582f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    private PasswordEntryKeyboardHelper mKeyboardHelper;
59122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private boolean mIsAlphaMode;
60122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private Button mCancelButton;
61122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private Button mNextButton;
6200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
6300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
6400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private static Handler mHandler = new Handler();
6500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private static final int CONFIRM_EXISTING_REQUEST = 58;
6600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    static final int RESULT_FINISHED = RESULT_FIRST_USER;
6700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private static final long ERROR_MESSAGE_TIMEOUT = 3000;
6800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
6900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    /**
7000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     * Keep track internally of where the user is in choosing a pattern.
7100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     */
7200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected enum Stage {
7300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
74122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        Introduction(R.string.lockpassword_choose_your_password_header,
75122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_choose_your_pin_header,
76122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_continue_label),
77122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
78122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        NeedToConfirm(R.string.lockpassword_confirm_your_password_header,
79122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_confirm_your_pin_header,
80122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_ok_label),
81122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
82122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match,
83122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_confirm_pins_dont_match,
84122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                R.string.lockpassword_continue_label);
8500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
8600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        /**
8700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller         * @param headerMessage The message displayed at the top.
8800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller         */
89122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) {
90122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            this.alphaHint = hintInAlpha;
91122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            this.numericHint = hintInNumeric;
92122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            this.buttonText = nextButtonText;
9300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
9400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
95122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        public final int alphaHint;
96122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        public final int numericHint;
97122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        public final int buttonText;
9800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
9900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
10000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    @Override
10100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void onCreate(Bundle savedInstanceState) {
10200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        super.onCreate(savedInstanceState);
10347d380f1e6c823cea444004cb799d4c791145cc6Jim Miller        mLockPatternUtils = new LockPatternUtils(this);
104af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        mRequestedQuality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality);
10570d5c3a0139899e5f4d425c8ab2d68f0dfc5c6daJim Miller        mPasswordMinLength = getIntent().getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength);
10670d5c3a0139899e5f4d425c8ab2d68f0dfc5c6daJim Miller        mPasswordMaxLength = getIntent().getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
107af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        int minMode = mLockPatternUtils.getRequestedPasswordQuality();
108af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (mRequestedQuality < minMode) {
109af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            mRequestedQuality = minMode;
110abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn        }
111abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn        int minLength = mLockPatternUtils.getRequestedMinimumPasswordLength();
112abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn        if (mPasswordMinLength < minLength) {
113abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn            mPasswordMinLength = minLength;
11447d380f1e6c823cea444004cb799d4c791145cc6Jim Miller        }
11500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        initViews();
11600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
11700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        if (savedInstanceState == null) {
11800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            updateStage(Stage.Introduction);
11900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST);
12000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
12100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
12200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
12300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private void initViews() {
1242f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        setContentView(R.layout.choose_lock_password);
1252f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        // Disable IME on our window since we provide our own keyboard
1262f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
1272f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1282f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
129122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mCancelButton = (Button) findViewById(R.id.cancel_button);
130122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mCancelButton.setOnClickListener(this);
131122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton = (Button) findViewById(R.id.next_button);
132122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton.setOnClickListener(this);
1332f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
1342f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
1352f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mPasswordEntry = (TextView) findViewById(R.id.password_entry);
136122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mPasswordEntry.setOnEditorActionListener(this);
137122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mPasswordEntry.addTextChangedListener(this);
1382f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
139af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
140af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality;
1412f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
142122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
143122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
1442f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller                : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
1452f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
14600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHeaderText = (TextView) findViewById(R.id.headerText);
1472f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView.requestFocus();
1482f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    }
1492f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
1502f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    @Override
1512f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    protected void onResume() {
1522f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        super.onResume();
1532f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        updateStage(mUiStage);
1542f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView.requestFocus();
15500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
15600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
15700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    @Override
158122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    protected void onSaveInstanceState(Bundle outState) {
159122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        super.onSaveInstanceState(outState);
160122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        outState.putString(KEY_UI_STAGE, mUiStage.name());
161122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        outState.putString(KEY_FIRST_PIN, mFirstPin);
162122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
163122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
164122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    @Override
165122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    protected void onRestoreInstanceState(Bundle savedInstanceState) {
166122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        super.onRestoreInstanceState(savedInstanceState);
167122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        String state = savedInstanceState.getString(KEY_UI_STAGE);
168122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
169122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (state != null) {
170122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mUiStage = Stage.valueOf(state);
171122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            updateStage(mUiStage);
172122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
173122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
174122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
175122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    @Override
17600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void onActivityResult(int requestCode, int resultCode,
17700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            Intent data) {
17800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        super.onActivityResult(requestCode, resultCode, data);
17900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        switch (requestCode) {
18000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            case CONFIRM_EXISTING_REQUEST:
18100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                if (resultCode != Activity.RESULT_OK) {
18200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                    setResult(RESULT_FINISHED);
18300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                    finish();
18400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                }
18500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
18600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
18700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
18800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
18900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void updateStage(Stage stage) {
19000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mUiStage = stage;
191122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        updateUi();
19200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
19300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
19400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    /**
19500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     * Validates PIN and returns a message to display if PIN fails test.
196af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller     * @param password the raw password the user typed in
197af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller     * @return error message to show to user or null if password is OK
19800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     */
199af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller    private String validatePassword(String password) {
200af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (password.length() < mPasswordMinLength) {
201122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return getString(mIsAlphaMode ?
202122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    R.string.lockpassword_password_too_short
203122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    : R.string.lockpassword_pin_too_short, mPasswordMinLength);
20400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
205af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (password.length() > mPasswordMaxLength) {
206122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return getString(mIsAlphaMode ?
207122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    R.string.lockpassword_password_too_long
208122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    : R.string.lockpassword_pin_too_long, mPasswordMaxLength);
20900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
210122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        boolean hasAlpha = false;
211122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        boolean hasDigit = false;
212122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        boolean hasSymbol = false;
213af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        for (int i = 0; i < password.length(); i++) {
214af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            char c = password.charAt(i);
215122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            // allow non white space Latin-1 characters only
216122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (c <= 32 || c > 127) {
217122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                return getString(R.string.lockpassword_illegal_character);
21800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
219122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (c >= '0' && c <= '9') {
220122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                hasDigit = true;
221122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
222122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                hasAlpha = true;
223122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
224122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                hasSymbol = true;
22500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
22600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
227af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
228af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                && (hasAlpha | hasSymbol)) {
229af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            // This shouldn't be possible unless user finds some way to bring up soft keyboard
230af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            return getString(R.string.lockpassword_pin_contains_non_digits);
231af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        } else {
232af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
233af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    == mRequestedQuality;
234af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
235af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    == mRequestedQuality;
236af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean symbolic = false; // not yet
237af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            if ((alphabetic || alphanumeric) && !hasAlpha) {
238af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_alpha);
239af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
240af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            if (alphanumeric && !hasDigit) {
241af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_digit);
242af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
243af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            if (symbolic && !hasSymbol) {
244af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_symbol);
245af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
246122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
24700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        return null;
24800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
24900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
250122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private void handleNext() {
251122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        final String pin = mPasswordEntry.getText().toString();
252122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (TextUtils.isEmpty(pin)) {
253122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return;
254122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
255122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        String errorMsg = null;
256122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.Introduction) {
257122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            errorMsg = validatePassword(pin);
258122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (errorMsg == null) {
259122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mFirstPin = pin;
260122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                updateStage(Stage.NeedToConfirm);
261122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mPasswordEntry.setText("");
262122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
263122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        } else if (mUiStage == Stage.NeedToConfirm) {
264122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (mFirstPin.equals(pin)) {
265122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mLockPatternUtils.clearLock();
266af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
267122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                finish();
268122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
269122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                updateStage(Stage.ConfirmWrong);
270122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                CharSequence tmp = mPasswordEntry.getText();
271122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                if (tmp != null) {
272122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    Selection.setSelection((Spannable) tmp, 0, tmp.length());
273122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                }
274122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
275122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
276122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (errorMsg != null) {
277122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            showError(errorMsg, mUiStage);
278122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
279122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
280122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
28100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public void onClick(View v) {
28200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        switch (v.getId()) {
2832f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller            case R.id.next_button:
284122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                handleNext();
28500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
28600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
2872f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller            case R.id.cancel_button:
28800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                finish();
28900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
29000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
29100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
29200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
29300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private void showError(String msg, final Stage next) {
29400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHeaderText.setText(msg);
29500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHandler.postDelayed(new Runnable() {
29600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            public void run() {
29700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                updateStage(next);
29800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
29900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }, ERROR_MESSAGE_TIMEOUT);
30000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
301122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
302122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
303122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        // Check if this was the result of hitting the enter key
304122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (actionId == EditorInfo.IME_NULL) {
305122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            handleNext();
306122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return true;
307122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
308122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        return false;
309122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
310122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
311122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    /**
312122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller     * Update the hint based on current Stage and length of password entry
313122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller     */
314122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private void updateUi() {
315af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        String password = mPasswordEntry.getText().toString();
316af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        final int length = password.length();
317122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.Introduction && length > 0) {
318122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (length < mPasswordMinLength) {
319122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
320122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                        : R.string.lockpassword_pin_too_short, mPasswordMinLength);
321122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mHeaderText.setText(msg);
322122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mNextButton.setEnabled(false);
323122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
324af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                String error = validatePassword(password);
325af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                if (error != null) {
326af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mHeaderText.setText(error);
327af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mNextButton.setEnabled(false);
328af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                } else {
329af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mHeaderText.setText(R.string.lockpassword_press_continue);
330af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mNextButton.setEnabled(true);
331af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                }
332122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
333122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        } else {
334122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
335122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mNextButton.setEnabled(length > 0);
336122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
337122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton.setText(mUiStage.buttonText);
338122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
339122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
340122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void afterTextChanged(Editable s) {
341122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        // Changing the text while error displayed resets to NeedToConfirm state
342122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.ConfirmWrong) {
343122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mUiStage = Stage.NeedToConfirm;
344122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
345122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        updateUi();
346122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
347122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
348122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
349122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
350122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
351122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
352122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void onTextChanged(CharSequence s, int start, int before, int count) {
353122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
354122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
35500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller}
356