ChooseLockPassword.java revision abc3dc64cf61c9f5c28b6f2640b221d63cb86a0a
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings; 18 19import java.util.regex.Matcher; 20import java.util.regex.Pattern; 21 22import com.android.internal.widget.LockPatternUtils; 23import com.android.settings.ChooseLockPattern.LeftButtonMode; 24import com.android.settings.ChooseLockPattern.RightButtonMode; 25import com.android.settings.ChooseLockPattern.Stage; 26 27import android.app.Activity; 28import android.content.Intent; 29import android.os.Bundle; 30import android.os.Handler; 31import android.text.Editable; 32import android.text.TextUtils; 33import android.view.View; 34import android.view.View.OnClickListener; 35import android.widget.Button; 36import android.widget.TextView; 37 38 39public class ChooseLockPassword extends Activity implements OnClickListener { 40 private final int digitIds[] = new int[] { R.id.zero, R.id.one, R.id.two, R.id.three, 41 R.id.four, R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine }; 42 private TextView mPasswordTextView; 43 private int mPasswordMinLength = 4; 44 private int mPasswordMaxLength = 8; 45 private LockPatternUtils mLockPatternUtils; 46 private int mRequestedMode = LockPatternUtils.MODE_PIN; 47 private ChooseLockSettingsHelper mChooseLockSettingsHelper; 48 private com.android.settings.ChooseLockPassword.Stage mUiStage = Stage.Introduction; 49 private TextView mHeaderText; 50 private String mFirstPin; 51 public static final String PASSWORD_MIN_KEY = "lockscreen.password_min"; 52 public static final String PASSWORD_MAX_KEY = "lockscreen.password_max"; 53 private static Handler mHandler = new Handler(); 54 private static final int CONFIRM_EXISTING_REQUEST = 58; 55 static final int RESULT_FINISHED = RESULT_FIRST_USER; 56 private static final long ERROR_MESSAGE_TIMEOUT = 3000; 57 58 /** 59 * Keep track internally of where the user is in choosing a pattern. 60 */ 61 protected enum Stage { 62 63 Introduction(R.string.lockpassword_choose_your_password_header), 64 NeedToConfirm(R.string.lockpassword_confirm_your_password_header), 65 ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match), 66 ChoiceConfirmed(R.string.lockpassword_password_confirmed_header); 67 68 /** 69 * @param headerMessage The message displayed at the top. 70 */ 71 Stage(int headerMessage) { 72 this.headerMessage = headerMessage; 73 } 74 75 final int headerMessage; 76 } 77 78 @Override 79 protected void onCreate(Bundle savedInstanceState) { 80 super.onCreate(savedInstanceState); 81 mLockPatternUtils = new LockPatternUtils(this); 82 mRequestedMode = getIntent().getIntExtra("password_mode", mRequestedMode); 83 mPasswordMinLength = getIntent().getIntExtra("password_min_length", mPasswordMinLength); 84 mPasswordMaxLength = getIntent().getIntExtra("password_max_length", mPasswordMaxLength); 85 int minMode = mLockPatternUtils.getRequestedPasswordMode(); 86 if (mRequestedMode < minMode) { 87 mRequestedMode = minMode; 88 } 89 int minLength = mLockPatternUtils.getRequestedMinimumPasswordLength(); 90 if (mPasswordMinLength < minLength) { 91 mPasswordMinLength = minLength; 92 } 93 initViews(); 94 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this); 95 if (savedInstanceState == null) { 96 updateStage(Stage.Introduction); 97 mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST); 98 } 99 } 100 101 private void initViews() { 102 switch(mRequestedMode) { 103 case LockPatternUtils.MODE_PIN: 104 case LockPatternUtils.MODE_PASSWORD: 105 case LockPatternUtils.MODE_PATTERN: 106 setContentView(R.layout.choose_lock_pin); 107 // TODO: alphanumeric layout 108 // setContentView(R.layout.choose_lock_password); 109 for (int i = 0; i < digitIds.length; i++) { 110 Button button = (Button) findViewById(digitIds[i]); 111 button.setOnClickListener(this); 112 button.setText(Integer.toString(i)); 113 } 114 break; 115 } 116 findViewById(R.id.ok).setOnClickListener(this); 117 findViewById(R.id.cancel).setOnClickListener(this); 118 findViewById(R.id.backspace).setOnClickListener(this); 119 mPasswordTextView = (TextView) findViewById(R.id.pinDisplay); 120 mHeaderText = (TextView) findViewById(R.id.headerText); 121 } 122 123 @Override 124 protected void onActivityResult(int requestCode, int resultCode, 125 Intent data) { 126 super.onActivityResult(requestCode, resultCode, data); 127 switch (requestCode) { 128 case CONFIRM_EXISTING_REQUEST: 129 if (resultCode != Activity.RESULT_OK) { 130 setResult(RESULT_FINISHED); 131 finish(); 132 } 133 break; 134 } 135 } 136 137 protected void updateStage(Stage stage) { 138 mHeaderText.setText(stage.headerMessage); 139 mPasswordTextView.setText(""); 140 mUiStage = stage; 141 } 142 143 /** 144 * Validates PIN and returns a message to display if PIN fails test. 145 * @param pin 146 * @return message id to display to user 147 */ 148 private String validatePassword(String pin) { 149 if (pin.length() < mPasswordMinLength) { 150 return getString(R.string.pin_password_too_short, mPasswordMinLength); 151 } 152 if (pin.length() > mPasswordMaxLength) { 153 return getString(R.string.pin_password_too_long, mPasswordMaxLength); 154 } 155 if (LockPatternUtils.MODE_PIN == mRequestedMode) { 156 Pattern p = Pattern.compile("[0-9]+"); 157 Matcher m = p.matcher(pin); 158 if (!m.find()) { 159 return getString(R.string.pin_password_contains_non_digits); 160 } 161 } else if (LockPatternUtils.MODE_PASSWORD == mRequestedMode) { 162 // allow Latin-1 characters only 163 for (int i = 0; i < pin.length(); i++) { 164 char c = pin.charAt(i); 165 if (c <= 32 || c > 127) { 166 return getString(R.string.pin_password_illegal_character); 167 } 168 } 169 } 170 return null; 171 } 172 173 public void onClick(View v) { 174 switch (v.getId()) { 175 case R.id.ok: 176 { 177 final String pin = mPasswordTextView.getText().toString(); 178 if (TextUtils.isEmpty(pin)) { 179 break; 180 } 181 String errorMsg = null; 182 if (mUiStage == Stage.Introduction) { 183 errorMsg = validatePassword(pin); 184 if (errorMsg == null) { 185 mFirstPin = pin; 186 updateStage(Stage.NeedToConfirm); 187 } 188 } else if (mUiStage == Stage.NeedToConfirm) { 189 if (mFirstPin.equals(pin)) { 190 // TODO: move these to LockPatternUtils 191 mLockPatternUtils.setLockPatternEnabled(false); 192 mLockPatternUtils.saveLockPattern(null); 193 mLockPatternUtils.saveLockPassword(pin, mRequestedMode); 194 finish(); 195 } else { 196 int msg = R.string.lockpassword_confirm_passwords_dont_match; 197 errorMsg = getString(msg); 198 } 199 } 200 if (errorMsg != null) { 201 showError(errorMsg, Stage.Introduction); 202 } 203 } 204 break; 205 206 case R.id.backspace: 207 { 208 final Editable digits = mPasswordTextView.getEditableText(); 209 final int len = digits.length(); 210 if (len > 0) { 211 digits.delete(len-1, len); 212 } 213 } 214 break; 215 216 case R.id.cancel: 217 finish(); 218 break; 219 220 default: 221 // Digits 222 for (int i = 0; i < digitIds.length; i++) { 223 if (v.getId() == digitIds[i]) { 224 mPasswordTextView.append(Integer.toString(i)); 225 return; 226 } 227 } 228 break; 229 } 230 } 231 232 private void showError(String msg, final Stage next) { 233 mHeaderText.setText(msg); 234 mPasswordTextView.setText(""); 235 mHandler.postDelayed(new Runnable() { 236 public void run() { 237 updateStage(next); 238 } 239 }, ERROR_MESSAGE_TIMEOUT); 240 } 241} 242