| /* | 
 |  * 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); | 
 |     } | 
 | } |