Home | History | Annotate | Download | only in phone
      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