1 /* 2 * Copyright (C) 2006 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 17 package com.android.phone; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.content.Intent; 22 import android.content.res.Resources; 23 import android.os.AsyncResult; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.Message; 27 import android.text.method.DigitsKeyListener; 28 import android.util.Log; 29 import android.view.View; 30 import android.widget.Button; 31 import android.widget.EditText; 32 import android.widget.LinearLayout; 33 import android.widget.ScrollView; 34 import android.widget.TextView; 35 import android.widget.Toast; 36 37 import com.android.internal.telephony.CommandException; 38 import com.android.internal.telephony.IccCard; 39 import com.android.internal.telephony.Phone; 40 import com.android.internal.telephony.PhoneFactory; 41 42 /** 43 * "Change ICC PIN" UI for the Phone app. 44 */ 45 public class ChangeIccPinScreen extends Activity { 46 private static final String LOG_TAG = PhoneApp.LOG_TAG; 47 private static final boolean DBG = false; 48 49 private static final int EVENT_PIN_CHANGED = 100; 50 51 private enum EntryState { 52 ES_PIN, 53 ES_PUK 54 } 55 56 private EntryState mState; 57 58 private static final int NO_ERROR = 0; 59 private static final int PIN_MISMATCH = 1; 60 private static final int PIN_INVALID_LENGTH = 2; 61 62 private static final int MIN_PIN_LENGTH = 4; 63 private static final int MAX_PIN_LENGTH = 8; 64 65 private Phone mPhone; 66 private boolean mChangePin2; 67 private TextView mBadPinError; 68 private TextView mMismatchError; 69 private EditText mOldPin; 70 private EditText mNewPin1; 71 private EditText mNewPin2; 72 private EditText mPUKCode; 73 private Button mButton; 74 private Button mPUKSubmit; 75 private ScrollView mScrollView; 76 77 private LinearLayout mIccPUKPanel; 78 79 private Handler mHandler = new Handler() { 80 public void handleMessage(Message msg) { 81 switch (msg.what) { 82 case EVENT_PIN_CHANGED: 83 AsyncResult ar = (AsyncResult) msg.obj; 84 handleResult(ar); 85 break; 86 } 87 88 return; 89 } 90 }; 91 92 public void onCreate(Bundle icicle) { 93 super.onCreate(icicle); 94 95 mPhone = PhoneFactory.getDefaultPhone(); 96 97 resolveIntent(); 98 99 setContentView(R.layout.change_sim_pin_screen); 100 101 mOldPin = (EditText) findViewById(R.id.old_pin); 102 mOldPin.setKeyListener(DigitsKeyListener.getInstance()); 103 mOldPin.setMovementMethod(null); 104 mOldPin.setOnClickListener(mClicked); 105 106 mNewPin1 = (EditText) findViewById(R.id.new_pin1); 107 mNewPin1.setKeyListener(DigitsKeyListener.getInstance()); 108 mNewPin1.setMovementMethod(null); 109 mNewPin1.setOnClickListener(mClicked); 110 111 mNewPin2 = (EditText) findViewById(R.id.new_pin2); 112 mNewPin2.setKeyListener(DigitsKeyListener.getInstance()); 113 mNewPin2.setMovementMethod(null); 114 mNewPin2.setOnClickListener(mClicked); 115 116 mBadPinError = (TextView) findViewById(R.id.bad_pin); 117 mMismatchError = (TextView) findViewById(R.id.mismatch); 118 119 mButton = (Button) findViewById(R.id.button); 120 mButton.setOnClickListener(mClicked); 121 122 mScrollView = (ScrollView) findViewById(R.id.scroll); 123 124 mPUKCode = (EditText) findViewById(R.id.puk_code); 125 mPUKCode.setKeyListener(DigitsKeyListener.getInstance()); 126 mPUKCode.setMovementMethod(null); 127 mPUKCode.setOnClickListener(mClicked); 128 129 mPUKSubmit = (Button) findViewById(R.id.puk_submit); 130 mPUKSubmit.setOnClickListener(mClicked); 131 132 mIccPUKPanel = (LinearLayout) findViewById(R.id.puk_panel); 133 134 int id = mChangePin2 ? R.string.change_pin2 : R.string.change_pin; 135 setTitle(getResources().getText(id)); 136 137 mState = EntryState.ES_PIN; 138 } 139 140 private void resolveIntent() { 141 Intent intent = getIntent(); 142 mChangePin2 = intent.getBooleanExtra("pin2", mChangePin2); 143 } 144 145 private void reset() { 146 mScrollView.scrollTo(0, 0); 147 mBadPinError.setVisibility(View.GONE); 148 mMismatchError.setVisibility(View.GONE); 149 } 150 151 private int validateNewPin(String p1, String p2) { 152 if (p1 == null) { 153 return PIN_INVALID_LENGTH; 154 } 155 156 if (!p1.equals(p2)) { 157 return PIN_MISMATCH; 158 } 159 160 int len1 = p1.length(); 161 162 if (len1 < MIN_PIN_LENGTH || len1 > MAX_PIN_LENGTH) { 163 return PIN_INVALID_LENGTH; 164 } 165 166 return NO_ERROR; 167 } 168 169 private View.OnClickListener mClicked = new View.OnClickListener() { 170 public void onClick(View v) { 171 if (v == mOldPin) { 172 mNewPin1.requestFocus(); 173 } else if (v == mNewPin1) { 174 mNewPin2.requestFocus(); 175 } else if (v == mNewPin2) { 176 mButton.requestFocus(); 177 } else if (v == mButton) { 178 IccCard iccCardInterface = mPhone.getIccCard(); 179 if (iccCardInterface != null) { 180 String oldPin = mOldPin.getText().toString(); 181 String newPin1 = mNewPin1.getText().toString(); 182 String newPin2 = mNewPin2.getText().toString(); 183 184 int error = validateNewPin(newPin1, newPin2); 185 186 switch (error) { 187 case PIN_INVALID_LENGTH: 188 case PIN_MISMATCH: 189 mNewPin1.getText().clear(); 190 mNewPin2.getText().clear(); 191 mMismatchError.setVisibility(View.VISIBLE); 192 193 Resources r = getResources(); 194 CharSequence text; 195 196 if (error == PIN_MISMATCH) { 197 text = r.getString(R.string.mismatchPin); 198 } else { 199 text = r.getString(R.string.invalidPin); 200 } 201 202 mMismatchError.setText(text); 203 break; 204 205 default: 206 Message callBack = Message.obtain(mHandler, 207 EVENT_PIN_CHANGED); 208 209 if (DBG) log("change pin attempt: old=" + oldPin + 210 ", newPin=" + newPin1); 211 212 reset(); 213 214 if (mChangePin2) { 215 iccCardInterface.changeIccFdnPassword(oldPin, 216 newPin1, callBack); 217 } else { 218 iccCardInterface.changeIccLockPassword(oldPin, 219 newPin1, callBack); 220 } 221 222 // TODO: show progress panel 223 } 224 } 225 } else if (v == mPUKCode) { 226 mPUKSubmit.requestFocus(); 227 } else if (v == mPUKSubmit) { 228 mPhone.getIccCard().supplyPuk2(mPUKCode.getText().toString(), 229 mNewPin1.getText().toString(), 230 Message.obtain(mHandler, EVENT_PIN_CHANGED)); 231 } 232 } 233 }; 234 235 private void handleResult(AsyncResult ar) { 236 if (ar.exception == null) { 237 if (DBG) log("handleResult: success!"); 238 239 if (mState == EntryState.ES_PUK) { 240 mScrollView.setVisibility(View.VISIBLE); 241 mIccPUKPanel.setVisibility(View.GONE); 242 } 243 // TODO: show success feedback 244 showConfirmation(); 245 246 mHandler.postDelayed(new Runnable() { 247 public void run() { 248 finish(); 249 } 250 }, 3000); 251 252 } else if (ar.exception instanceof CommandException 253 /* && ((CommandException)ar.exception).getCommandError() == 254 CommandException.Error.PASSWORD_INCORRECT */ ) { 255 if (mState == EntryState.ES_PIN) { 256 if (DBG) log("handleResult: pin failed!"); 257 mOldPin.getText().clear(); 258 mBadPinError.setVisibility(View.VISIBLE); 259 CommandException ce = (CommandException) ar.exception; 260 if (ce.getCommandError() == CommandException.Error.SIM_PUK2) { 261 if (DBG) log("handleResult: puk requested!"); 262 mState = EntryState.ES_PUK; 263 displayPUKAlert(); 264 mScrollView.setVisibility(View.GONE); 265 mIccPUKPanel.setVisibility(View.VISIBLE); 266 mPUKCode.requestFocus(); 267 } 268 } else if (mState == EntryState.ES_PUK) { 269 //should really check to see if the error is CommandException.PASSWORD_INCORRECT... 270 if (DBG) log("handleResult: puk2 failed!"); 271 displayPUKAlert(); 272 mPUKCode.getText().clear(); 273 mPUKCode.requestFocus(); 274 } 275 } 276 } 277 278 private AlertDialog mPUKAlert; 279 private void displayPUKAlert () { 280 if (mPUKAlert == null) { 281 mPUKAlert = new AlertDialog.Builder(this) 282 .setMessage (R.string.puk_requested) 283 .setCancelable(false) 284 .show(); 285 } else { 286 mPUKAlert.show(); 287 } 288 //TODO: The 3 second delay here is somewhat arbitrary, reflecting the values 289 //used elsewhere for similar code. This should get revisited with the framework 290 //crew to see if there is some standard we should adhere to. 291 mHandler.postDelayed(new Runnable() { 292 public void run() { 293 mPUKAlert.dismiss(); 294 } 295 }, 3000); 296 } 297 298 private void showConfirmation() { 299 int id = mChangePin2 ? R.string.pin2_changed : R.string.pin_changed; 300 Toast.makeText(this, id, Toast.LENGTH_SHORT).show(); 301 } 302 303 private void log(String msg) { 304 String prefix = mChangePin2 ? "[ChgPin2]" : "[ChgPin]"; 305 Log.d(LOG_TAG, prefix + msg); 306 } 307 } 308