47be268322936ea81ec6c7c36b06bb5e0311f5e4
[android/platform/packages/apps/Phone.git] / src / com / android / phone / ChangeIccPinScreen.java
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 }