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