/* * 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.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.Bundle; import android.text.Editable; import android.text.Spannable; import android.text.TextUtils; import android.text.TextWatcher; import android.text.method.DialerKeyListener; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.IccCard; /** * Panel where you enter your PIN to unlock the SIM card. */ public class IccPinUnlockPanel extends IccPanel { private static final boolean DBG = false; private static final int EVENT_ICC_UNLOCKED_RESULT = 100; private enum IccLockState { UNLOCKED, REQUIRE_PIN, REQUIRE_PUK, REQUIRE_NEW_PIN, VERIFY_NEW_PIN, VERIFY_NEW_PIN_FAILED }; private IccLockState mState; private String mPUKCode; private String mNewPinCode; private EditText mEntry; private TextView mFailure; private TextView mLabel; private TextView mStatus; private Button mUnlockButton; private Button mDismissButton; private LinearLayout mUnlockPane; private LinearLayout mUnlockInProgressPane; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case EVENT_ICC_UNLOCKED_RESULT: AsyncResult ar = (AsyncResult) msg.obj; handleUnlockResult(ar); break; } } }; private class MyTextWatcher implements TextWatcher { Context mContext; public MyTextWatcher(Context context) { mContext = context; } public void beforeTextChanged(CharSequence buffer, int start, int olen, int nlen) { } public void onTextChanged(CharSequence buffer, int start, int olen, int nlen) { } public void afterTextChanged(Editable buffer) { if (SpecialCharSequenceMgr.handleChars( mContext, buffer.toString())) { mEntry.getText().clear(); } } } public IccPinUnlockPanel(Context context) { super(context); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sim_unlock); updateState(); initView(); updateView(); } @Override protected void onStart() { super.onStart(); if (updateState()) { updateView(); // need to update the view only if state changed } } /** * @return Whether the state changed. */ boolean updateState() { PhoneApp app = PhoneApp.getInstance(); IccCard iccCardInterface = app.phone.getIccCard(); try { if (iccCardInterface.getState() == IccCard.State.PUK_REQUIRED) { if (getState() != IccLockState.REQUIRE_PUK) { setState(IccLockState.REQUIRE_PUK); return true; } } else if (getState() != IccLockState.REQUIRE_PIN){ setState(IccLockState.REQUIRE_PIN); return true; } } catch (Exception ex) { } return false; } void setState(IccLockState state) { mState = state; } IccLockState getState() { return mState; } void initView() { mUnlockPane = (LinearLayout) findViewById(R.id.simPINPane); mUnlockInProgressPane = (LinearLayout) findViewById(R.id.progress); mEntry = (EditText) findViewById(R.id.entry); mEntry.setKeyListener(DialerKeyListener.getInstance()); mEntry.setMovementMethod(null); mEntry.setOnClickListener(mUnlockListener); // set up the text watcher CharSequence text = mEntry.getText(); Spannable span = (Spannable) text; span.setSpan(new MyTextWatcher(this.getContext()), 0, text.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); mFailure = (TextView) findViewById(R.id.failure); mLabel = (TextView) findViewById(R.id.label); mStatus = (TextView) findViewById(R.id.status); mUnlockButton = (Button) findViewById(R.id.unlock); mUnlockButton.setOnClickListener(mUnlockListener); mDismissButton = (Button) findViewById(R.id.dismiss); // if we are using the ICC pin for keyguard password, force the // user to enter the correct PIN to proceed. Otherwise, we won't // know what the correct keyguard password is. mDismissButton.setOnClickListener(mDismissListener); } void updateView() { Context context = getContext(); switch (mState) { case REQUIRE_PIN: mLabel.setText(context.getText(R.string.enterPin)); break; case REQUIRE_PUK: mLabel.setText(context.getText(R.string.enterPuk)); mUnlockButton.setText( context.getText(R.string.buttonTxtContinue)); break; case REQUIRE_NEW_PIN: hideIncorrectPinMessage(); mLabel.setText(context.getText(R.string.enterNewPin)); break; case VERIFY_NEW_PIN: mLabel.setText(context.getText(R.string.verifyNewPin)); break; case VERIFY_NEW_PIN_FAILED: mLabel.setText(context.getText(R.string.verifyFailed)); setState(IccLockState.REQUIRE_NEW_PIN); break; } mEntry.getText().clear(); mEntry.requestFocus(View.FOCUS_FORWARD); } public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; } return super.onKeyDown(keyCode, event); } void handleUnlockResult(AsyncResult ar) { if (ar.exception == null) { handleSuccess(); return; } // pin/puk unlock failed! if (ar.exception instanceof com.android.internal.telephony.CommandException && ((CommandException) ar.exception).getCommandError() == CommandException.Error.PASSWORD_INCORRECT) { hidePinUnlockInProgress(); handleFailure(); } // PENDING: any other failure types? } void handleSuccess() { if (DBG) log("unlock successful!"); showUnlockSuccess(); // store the ICC pin in memory, to be used later for keyguard lock // and radio reboots. PhoneApp.getInstance().setCachedSimPin(mEntry.getText().toString()); } void handleFailure() { if (DBG) log("unlock failed"); showIncorrectPinMessage(); mEntry.getText().clear(); updateState(); updateView(); } void showIncorrectPinMessage() { CharSequence msg; Context context = getContext(); if (getState() == IccLockState.REQUIRE_PIN) { msg = context.getText(R.string.badPin); } else { msg = context.getText(R.string.badPuk); } mFailure.setText(msg); mFailure.setVisibility(View.VISIBLE); } void hideIncorrectPinMessage() { mFailure.setVisibility(View.GONE); } void showUnlockInProgress() { mUnlockInProgressPane.setVisibility(View.VISIBLE); mUnlockPane.setVisibility(View.GONE); } void hidePinUnlockInProgress() { mUnlockInProgressPane.setVisibility(View.GONE); mUnlockPane.setVisibility(View.VISIBLE); } void showUnlockSuccess() { mStatus.setText(getContext().getText(R.string.pinUnlocked)); mHandler.postDelayed( new Runnable() { public void run() { dismiss(); } }, 1000); } private boolean verifyNewPin(String pin2) { if (mNewPinCode.equals(pin2)) { return true; } return false; } //***** Listeners View.OnClickListener mUnlockListener = new View.OnClickListener() { public void onClick(View v) { String code = mEntry.getText().toString(); if (TextUtils.isEmpty(code)) { return; } PhoneApp app = PhoneApp.getInstance(); IccCard iccCardInterface = app.phone.getIccCard(); if (iccCardInterface != null) { Message callBack = Message.obtain(mHandler, EVENT_ICC_UNLOCKED_RESULT); switch (mState) { case REQUIRE_PIN: if (DBG) log("unlock attempt: PIN code entered = " + code); showUnlockInProgress(); iccCardInterface.supplyPin(code, callBack); break; case REQUIRE_PUK: if (DBG) log("puk code entered, request for new pin"); mPUKCode = code; setState(IccLockState.REQUIRE_NEW_PIN); updateView(); break; case REQUIRE_NEW_PIN: if (DBG) log("new pin code entered, verify pin"); mNewPinCode = code; setState(IccLockState.VERIFY_NEW_PIN); updateView(); break; case VERIFY_NEW_PIN: if (DBG) log("new pin code re-entered"); if (verifyNewPin(code)) { // proceed showUnlockInProgress(); iccCardInterface.supplyPuk(mPUKCode, mNewPinCode, callBack); } else { setState(IccLockState.VERIFY_NEW_PIN_FAILED); updateView(); } break; } } } }; View.OnClickListener mDismissListener = new View.OnClickListener() { public void onClick(View v) { dismiss(); } }; private void log(String msg) { Log.v(TAG, "[SimPinUnlock] " + msg); } }