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);
107bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller
108bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller        final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
109af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        int minMode = mLockPatternUtils.getRequestedPasswordQuality();
110af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (mRequestedQuality < minMode) {
111af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            mRequestedQuality = minMode;
112abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn        }
113abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn        int minLength = mLockPatternUtils.getRequestedMinimumPasswordLength();
114abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn        if (mPasswordMinLength < minLength) {
115abc3dc64cf61c9f5c28b6f2640b221d63cb86a0aDianne Hackborn            mPasswordMinLength = minLength;
11647d380f1e6c823cea444004cb799d4c791145cc6Jim Miller        }
11700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        initViews();
11800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
11900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        if (savedInstanceState == null) {
12000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            updateStage(Stage.Introduction);
121bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller            if (confirmCredentials) {
1222deec7edc937b1d19df0a74c4cd0c5ee3ef33070Jim Miller                mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
1232deec7edc937b1d19df0a74c4cd0c5ee3ef33070Jim Miller                        null, null);
124bbb4afa19f75694c585506b0c091372d60e07ca7Jim Miller            }
12500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
12600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
12700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
12800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private void initViews() {
1292f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        setContentView(R.layout.choose_lock_password);
1302f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        // Disable IME on our window since we provide our own keyboard
1312f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
1322f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1332f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
134122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mCancelButton = (Button) findViewById(R.id.cancel_button);
135122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mCancelButton.setOnClickListener(this);
136122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton = (Button) findViewById(R.id.next_button);
137122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton.setOnClickListener(this);
1382f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
1392f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
1402f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mPasswordEntry = (TextView) findViewById(R.id.password_entry);
141122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mPasswordEntry.setOnEditorActionListener(this);
142122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mPasswordEntry.addTextChangedListener(this);
1432f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
144af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
145af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality;
1462f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
147122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
148122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
1492f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller                : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
1502f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
15100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHeaderText = (TextView) findViewById(R.id.headerText);
1522f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView.requestFocus();
1532f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    }
1542f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller
1552f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    @Override
1562f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller    protected void onResume() {
1572f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        super.onResume();
1582f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        updateStage(mUiStage);
1592f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller        mKeyboardView.requestFocus();
16000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
16100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
16200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    @Override
163122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    protected void onSaveInstanceState(Bundle outState) {
164122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        super.onSaveInstanceState(outState);
165122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        outState.putString(KEY_UI_STAGE, mUiStage.name());
166122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        outState.putString(KEY_FIRST_PIN, mFirstPin);
167122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
168122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
169122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    @Override
170122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    protected void onRestoreInstanceState(Bundle savedInstanceState) {
171122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        super.onRestoreInstanceState(savedInstanceState);
172122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        String state = savedInstanceState.getString(KEY_UI_STAGE);
173122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
174122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (state != null) {
175122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mUiStage = Stage.valueOf(state);
176122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            updateStage(mUiStage);
177122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
178122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
179122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
180122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    @Override
18100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void onActivityResult(int requestCode, int resultCode,
18200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            Intent data) {
18300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        super.onActivityResult(requestCode, resultCode, data);
18400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        switch (requestCode) {
18500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            case CONFIRM_EXISTING_REQUEST:
18600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                if (resultCode != Activity.RESULT_OK) {
18700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                    setResult(RESULT_FINISHED);
18800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                    finish();
18900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                }
19000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
19100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
19200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
19300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
19400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    protected void updateStage(Stage stage) {
19500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mUiStage = stage;
196122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        updateUi();
19700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
19800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
19900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    /**
20000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     * Validates PIN and returns a message to display if PIN fails test.
201af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller     * @param password the raw password the user typed in
202af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller     * @return error message to show to user or null if password is OK
20300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller     */
204af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller    private String validatePassword(String password) {
205af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (password.length() < mPasswordMinLength) {
206122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return getString(mIsAlphaMode ?
207122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    R.string.lockpassword_password_too_short
208122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    : R.string.lockpassword_pin_too_short, mPasswordMinLength);
20900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
210af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (password.length() > mPasswordMaxLength) {
211122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return getString(mIsAlphaMode ?
212122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    R.string.lockpassword_password_too_long
213122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    : R.string.lockpassword_pin_too_long, mPasswordMaxLength);
21400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
215122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        boolean hasAlpha = false;
216122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        boolean hasDigit = false;
217122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        boolean hasSymbol = false;
218af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        for (int i = 0; i < password.length(); i++) {
219af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            char c = password.charAt(i);
220122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            // allow non white space Latin-1 characters only
221122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (c <= 32 || c > 127) {
222122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                return getString(R.string.lockpassword_illegal_character);
22300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
224122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (c >= '0' && c <= '9') {
225122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                hasDigit = true;
226122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
227122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                hasAlpha = true;
228122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
229122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                hasSymbol = true;
23000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
23100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
232af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
233af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                && (hasAlpha | hasSymbol)) {
234af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            // This shouldn't be possible unless user finds some way to bring up soft keyboard
235af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            return getString(R.string.lockpassword_pin_contains_non_digits);
236af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        } else {
237af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
238af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    == mRequestedQuality;
239af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
240af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    == mRequestedQuality;
241af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            final boolean symbolic = false; // not yet
242af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            if ((alphabetic || alphanumeric) && !hasAlpha) {
243af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_alpha);
244af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
245af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            if (alphanumeric && !hasDigit) {
246af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_digit);
247af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
248af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            if (symbolic && !hasSymbol) {
249af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                return getString(R.string.lockpassword_password_requires_symbol);
250af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller            }
251122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
25200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        return null;
25300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
25400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
255122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private void handleNext() {
256122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        final String pin = mPasswordEntry.getText().toString();
257122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (TextUtils.isEmpty(pin)) {
258122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return;
259122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
260122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        String errorMsg = null;
261122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.Introduction) {
262122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            errorMsg = validatePassword(pin);
263122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (errorMsg == null) {
264122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mFirstPin = pin;
265122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                updateStage(Stage.NeedToConfirm);
266122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mPasswordEntry.setText("");
267122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
268122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        } else if (mUiStage == Stage.NeedToConfirm) {
269122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (mFirstPin.equals(pin)) {
270122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mLockPatternUtils.clearLock();
271af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
272122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                finish();
273122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
274122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                updateStage(Stage.ConfirmWrong);
275122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                CharSequence tmp = mPasswordEntry.getText();
276122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                if (tmp != null) {
277122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                    Selection.setSelection((Spannable) tmp, 0, tmp.length());
278122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                }
279122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
280122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
281122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (errorMsg != null) {
282122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            showError(errorMsg, mUiStage);
283122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
284122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
285122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
28600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    public void onClick(View v) {
28700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        switch (v.getId()) {
2882f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller            case R.id.next_button:
289122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                handleNext();
29000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
29100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
2922f9dbcb49174d85218dd18e3b2097d3b9fc789c7Jim Miller            case R.id.cancel_button:
29300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                finish();
29400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                break;
29500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }
29600d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
29700d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller
29800d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    private void showError(String msg, final Stage next) {
29900d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHeaderText.setText(msg);
30000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        mHandler.postDelayed(new Runnable() {
30100d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            public void run() {
30200d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller                updateStage(next);
30300d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller            }
30400d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller        }, ERROR_MESSAGE_TIMEOUT);
30500d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller    }
306122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
307122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
308122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        // Check if this was the result of hitting the enter key
309122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (actionId == EditorInfo.IME_NULL) {
310122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            handleNext();
311122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            return true;
312122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
313122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        return false;
314122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
315122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
316122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    /**
317122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller     * Update the hint based on current Stage and length of password entry
318122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller     */
319122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    private void updateUi() {
320af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        String password = mPasswordEntry.getText().toString();
321af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller        final int length = password.length();
322122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.Introduction && length > 0) {
323122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            if (length < mPasswordMinLength) {
324122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
325122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                        : R.string.lockpassword_pin_too_short, mPasswordMinLength);
326122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mHeaderText.setText(msg);
327122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller                mNextButton.setEnabled(false);
328122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            } else {
329af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                String error = validatePassword(password);
330af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                if (error != null) {
331af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mHeaderText.setText(error);
332af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mNextButton.setEnabled(false);
333af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                } else {
334af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mHeaderText.setText(R.string.lockpassword_press_continue);
335af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                    mNextButton.setEnabled(true);
336af366a3ed66dcb3c3ecb1dd101e5d8869b518598Jim Miller                }
337122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            }
338122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        } else {
339122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
340122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mNextButton.setEnabled(length > 0);
341122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
342122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        mNextButton.setText(mUiStage.buttonText);
343122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
344122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
345122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void afterTextChanged(Editable s) {
346122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        // Changing the text while error displayed resets to NeedToConfirm state
347122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        if (mUiStage == Stage.ConfirmWrong) {
348122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller            mUiStage = Stage.NeedToConfirm;
349122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        }
350122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller        updateUi();
351122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
352122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
353122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
354122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
355122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
356122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
357122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    public void onTextChanged(CharSequence s, int start, int before, int count) {
358122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller
359122b6c85a9bc7076eacc388142f8c4fccc5462c9Jim Miller    }
36000d2476d8fc122b4eef59d6be6f7aa41e9c56fdeJim Miller}
361