ChooseLockPassword.java revision 00d2476d8fc122b4eef59d6be6f7aa41e9c56fde
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(getContentResolver()); 82 mRequestedMode = getIntent().getIntExtra("password_mode", mRequestedMode); 83 mPasswordMinLength = getIntent().getIntExtra("password_min_length", mPasswordMinLength); 84 mPasswordMaxLength = getIntent().getIntExtra("password_max_length", mPasswordMaxLength); 85 initViews(); 86 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this); 87 if (savedInstanceState == null) { 88 updateStage(Stage.Introduction); 89 mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST); 90 } 91 } 92 93 private void initViews() { 94 if (LockPatternUtils.MODE_PIN == mRequestedMode 95 || LockPatternUtils.MODE_PASSWORD == mRequestedMode) { 96 setContentView(R.layout.choose_lock_pin); 97 // TODO: alphanumeric layout 98 // setContentView(R.layout.choose_lock_password); 99 for (int i = 0; i < digitIds.length; i++) { 100 Button button = (Button) findViewById(digitIds[i]); 101 button.setOnClickListener(this); 102 button.setText(Integer.toString(i)); 103 } 104 findViewById(R.id.ok).setOnClickListener(this); 105 findViewById(R.id.cancel).setOnClickListener(this); 106 } 107 findViewById(R.id.backspace).setOnClickListener(this); 108 mPasswordTextView = (TextView) findViewById(R.id.pinDisplay); 109 mHeaderText = (TextView) findViewById(R.id.headerText); 110 } 111 112 @Override 113 protected void onActivityResult(int requestCode, int resultCode, 114 Intent data) { 115 super.onActivityResult(requestCode, resultCode, data); 116 switch (requestCode) { 117 case CONFIRM_EXISTING_REQUEST: 118 if (resultCode != Activity.RESULT_OK) { 119 setResult(RESULT_FINISHED); 120 finish(); 121 } 122 break; 123 } 124 } 125 126 protected void updateStage(Stage stage) { 127 mHeaderText.setText(stage.headerMessage); 128 mPasswordTextView.setText(""); 129 mUiStage = stage; 130 } 131 132 /** 133 * Validates PIN and returns a message to display if PIN fails test. 134 * @param pin 135 * @return message id to display to user 136 */ 137 private String validatePassword(String pin) { 138 if (pin.length() < mPasswordMinLength) { 139 return getString(R.string.pin_password_too_short, mPasswordMinLength); 140 } 141 if (pin.length() > mPasswordMaxLength) { 142 return getString(R.string.pin_password_too_long, mPasswordMaxLength); 143 } 144 if (LockPatternUtils.MODE_PIN == mRequestedMode) { 145 Pattern p = Pattern.compile("[0-9]+"); 146 Matcher m = p.matcher(pin); 147 if (!m.find()) { 148 return getString(R.string.pin_password_contains_non_digits); 149 } 150 } else if (LockPatternUtils.MODE_PASSWORD == mRequestedMode) { 151 // allow Latin-1 characters only 152 for (int i = 0; i < pin.length(); i++) { 153 char c = pin.charAt(i); 154 if (c <= 32 || c > 127) { 155 return getString(R.string.pin_password_illegal_character); 156 } 157 } 158 } 159 return null; 160 } 161 162 public void onClick(View v) { 163 switch (v.getId()) { 164 case R.id.ok: 165 { 166 final String pin = mPasswordTextView.getText().toString(); 167 if (TextUtils.isEmpty(pin)) { 168 break; 169 } 170 String errorMsg = null; 171 if (mUiStage == Stage.Introduction) { 172 errorMsg = validatePassword(pin); 173 if (errorMsg == null) { 174 mFirstPin = pin; 175 updateStage(Stage.NeedToConfirm); 176 } 177 } else if (mUiStage == Stage.NeedToConfirm) { 178 if (mFirstPin.equals(pin)) { 179 // TODO: move these to LockPatternUtils 180 mLockPatternUtils.setLockPatternEnabled(false); 181 mLockPatternUtils.saveLockPattern(null); 182 183 184 mLockPatternUtils.saveLockPassword(pin); 185 finish(); 186 } else { 187 int msg = R.string.lockpassword_confirm_passwords_dont_match; 188 errorMsg = getString(msg); 189 } 190 } 191 if (errorMsg != null) { 192 showError(errorMsg, Stage.Introduction); 193 } 194 } 195 break; 196 197 case R.id.backspace: 198 { 199 final Editable digits = mPasswordTextView.getEditableText(); 200 final int len = digits.length(); 201 if (len > 0) { 202 digits.delete(len-1, len); 203 } 204 } 205 break; 206 207 case R.id.cancel: 208 finish(); 209 break; 210 211 default: 212 // Digits 213 for (int i = 0; i < digitIds.length; i++) { 214 if (v.getId() == digitIds[i]) { 215 mPasswordTextView.append(Integer.toString(i)); 216 return; 217 } 218 } 219 break; 220 } 221 } 222 223 private void showError(String msg, final Stage next) { 224 mHeaderText.setText(msg); 225 mPasswordTextView.setText(""); 226 mHandler.postDelayed(new Runnable() { 227 public void run() { 228 updateStage(next); 229 } 230 }, ERROR_MESSAGE_TIMEOUT); 231 } 232} 233