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