blob: 70bf4318c5f0f76d36ae8c7979cd230ea93dff8e [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.phone;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.method.DigitsKeyListener;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.Phone;
/**
* "Change ICC PIN" UI for the Phone app.
*/
public class ChangeIccPinScreen extends Activity {
private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
private static final boolean DBG = false;
private static final int EVENT_PIN_CHANGED = 100;
private enum EntryState {
ES_PIN,
ES_PUK
}
private EntryState mState;
private static final int NO_ERROR = 0;
private static final int PIN_MISMATCH = 1;
private static final int PIN_INVALID_LENGTH = 2;
private static final int MIN_PIN_LENGTH = 4;
private static final int MAX_PIN_LENGTH = 8;
private Phone mPhone;
private boolean mChangePin2;
private TextView mBadPinError;
private TextView mMismatchError;
private EditText mOldPin;
private EditText mNewPin1;
private EditText mNewPin2;
private EditText mPUKCode;
private Button mButton;
private Button mPUKSubmit;
private ScrollView mScrollView;
private LinearLayout mIccPUKPanel;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_PIN_CHANGED:
AsyncResult ar = (AsyncResult) msg.obj;
handleResult(ar);
break;
}
return;
}
};
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPhone = PhoneGlobals.getPhone();
resolveIntent();
setContentView(R.layout.change_sim_pin_screen);
mOldPin = (EditText) findViewById(R.id.old_pin);
mOldPin.setKeyListener(DigitsKeyListener.getInstance());
mOldPin.setMovementMethod(null);
mOldPin.setOnClickListener(mClicked);
mNewPin1 = (EditText) findViewById(R.id.new_pin1);
mNewPin1.setKeyListener(DigitsKeyListener.getInstance());
mNewPin1.setMovementMethod(null);
mNewPin1.setOnClickListener(mClicked);
mNewPin2 = (EditText) findViewById(R.id.new_pin2);
mNewPin2.setKeyListener(DigitsKeyListener.getInstance());
mNewPin2.setMovementMethod(null);
mNewPin2.setOnClickListener(mClicked);
mBadPinError = (TextView) findViewById(R.id.bad_pin);
mMismatchError = (TextView) findViewById(R.id.mismatch);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(mClicked);
mScrollView = (ScrollView) findViewById(R.id.scroll);
mPUKCode = (EditText) findViewById(R.id.puk_code);
mPUKCode.setKeyListener(DigitsKeyListener.getInstance());
mPUKCode.setMovementMethod(null);
mPUKCode.setOnClickListener(mClicked);
mPUKSubmit = (Button) findViewById(R.id.puk_submit);
mPUKSubmit.setOnClickListener(mClicked);
mIccPUKPanel = (LinearLayout) findViewById(R.id.puk_panel);
int id = mChangePin2 ? R.string.change_pin2 : R.string.change_pin;
setTitle(getResources().getText(id));
mState = EntryState.ES_PIN;
}
private void resolveIntent() {
Intent intent = getIntent();
mChangePin2 = intent.getBooleanExtra("pin2", mChangePin2);
}
private void reset() {
mScrollView.scrollTo(0, 0);
mBadPinError.setVisibility(View.GONE);
mMismatchError.setVisibility(View.GONE);
}
private int validateNewPin(String p1, String p2) {
if (p1 == null) {
return PIN_INVALID_LENGTH;
}
if (!p1.equals(p2)) {
return PIN_MISMATCH;
}
int len1 = p1.length();
if (len1 < MIN_PIN_LENGTH || len1 > MAX_PIN_LENGTH) {
return PIN_INVALID_LENGTH;
}
return NO_ERROR;
}
private View.OnClickListener mClicked = new View.OnClickListener() {
public void onClick(View v) {
if (v == mOldPin) {
mNewPin1.requestFocus();
} else if (v == mNewPin1) {
mNewPin2.requestFocus();
} else if (v == mNewPin2) {
mButton.requestFocus();
} else if (v == mButton) {
IccCard iccCardInterface = mPhone.getIccCard();
if (iccCardInterface != null) {
String oldPin = mOldPin.getText().toString();
String newPin1 = mNewPin1.getText().toString();
String newPin2 = mNewPin2.getText().toString();
int error = validateNewPin(newPin1, newPin2);
switch (error) {
case PIN_INVALID_LENGTH:
case PIN_MISMATCH:
mNewPin1.getText().clear();
mNewPin2.getText().clear();
mMismatchError.setVisibility(View.VISIBLE);
Resources r = getResources();
CharSequence text;
if (error == PIN_MISMATCH) {
text = r.getString(R.string.mismatchPin);
} else {
text = r.getString(R.string.invalidPin);
}
mMismatchError.setText(text);
break;
default:
Message callBack = Message.obtain(mHandler,
EVENT_PIN_CHANGED);
if (DBG) log("change pin attempt: old=" + oldPin +
", newPin=" + newPin1);
reset();
if (mChangePin2) {
iccCardInterface.changeIccFdnPassword(oldPin,
newPin1, callBack);
} else {
iccCardInterface.changeIccLockPassword(oldPin,
newPin1, callBack);
}
// TODO: show progress panel
}
}
} else if (v == mPUKCode) {
mPUKSubmit.requestFocus();
} else if (v == mPUKSubmit) {
mPhone.getIccCard().supplyPuk2(mPUKCode.getText().toString(),
mNewPin1.getText().toString(),
Message.obtain(mHandler, EVENT_PIN_CHANGED));
}
}
};
private void handleResult(AsyncResult ar) {
if (ar.exception == null) {
if (DBG) log("handleResult: success!");
if (mState == EntryState.ES_PUK) {
mScrollView.setVisibility(View.VISIBLE);
mIccPUKPanel.setVisibility(View.GONE);
}
// TODO: show success feedback
showConfirmation();
mHandler.postDelayed(new Runnable() {
public void run() {
finish();
}
}, 3000);
} else if (ar.exception instanceof CommandException
/* && ((CommandException)ar.exception).getCommandError() ==
CommandException.Error.PASSWORD_INCORRECT */ ) {
if (mState == EntryState.ES_PIN) {
if (DBG) log("handleResult: pin failed!");
mOldPin.getText().clear();
mBadPinError.setVisibility(View.VISIBLE);
CommandException ce = (CommandException) ar.exception;
if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
if (DBG) log("handleResult: puk requested!");
mState = EntryState.ES_PUK;
displayPUKAlert();
mScrollView.setVisibility(View.GONE);
mIccPUKPanel.setVisibility(View.VISIBLE);
mPUKCode.requestFocus();
}
} else if (mState == EntryState.ES_PUK) {
//should really check to see if the error is CommandException.PASSWORD_INCORRECT...
if (DBG) log("handleResult: puk2 failed!");
displayPUKAlert();
mPUKCode.getText().clear();
mPUKCode.requestFocus();
}
}
}
private AlertDialog mPUKAlert;
private void displayPUKAlert () {
if (mPUKAlert == null) {
mPUKAlert = new AlertDialog.Builder(this)
.setMessage (R.string.puk_requested)
.setCancelable(false)
.show();
} else {
mPUKAlert.show();
}
//TODO: The 3 second delay here is somewhat arbitrary, reflecting the values
//used elsewhere for similar code. This should get revisited with the framework
//crew to see if there is some standard we should adhere to.
mHandler.postDelayed(new Runnable() {
public void run() {
mPUKAlert.dismiss();
}
}, 3000);
}
private void showConfirmation() {
int id = mChangePin2 ? R.string.pin2_changed : R.string.pin_changed;
Toast.makeText(this, id, Toast.LENGTH_SHORT).show();
}
private void log(String msg) {
String prefix = mChangePin2 ? "[ChgPin2]" : "[ChgPin]";
Log.d(LOG_TAG, prefix + msg);
}
}