• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.AlertDialog;
20 import android.content.DialogInterface;
21 import android.os.AsyncResult;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.preference.PreferenceActivity;
26 import android.preference.PreferenceScreen;
27 import android.view.WindowManager;
28 import android.widget.Toast;
29 
30 import com.android.internal.telephony.CommandException;
31 import com.android.internal.telephony.Phone;
32 import com.android.internal.telephony.PhoneFactory;
33 
34 /**
35  * FDN settings UI for the Phone app.
36  * Rewritten to look and behave closer to the other preferences.
37  */
38 public class FdnSetting extends PreferenceActivity
39         implements EditPinPreference.OnPinEnteredListener, DialogInterface.OnCancelListener {
40 
41     private Phone mPhone;
42 
43     /**
44      * Events we handle.
45      * The first is used for toggling FDN enable, the second for the PIN change.
46      */
47     private static final int EVENT_PIN2_ENTRY_COMPLETE = 100;
48     private static final int EVENT_PIN2_CHANGE_COMPLETE = 200;
49 
50     // String keys for preference lookup
51     // We only care about the pin preferences here, the manage FDN contacts
52     // Preference is handled solely in xml.
53     private static final String BUTTON_FDN_ENABLE_KEY = "button_fdn_enable_key";
54     private static final String BUTTON_CHANGE_PIN2_KEY = "button_change_pin2_key";
55 
56     private EditPinPreference mButtonEnableFDN;
57     private EditPinPreference mButtonChangePin2;
58 
59     // State variables
60     private String mOldPin;
61     private String mNewPin;
62     private static final int PIN_CHANGE_OLD = 0;
63     private static final int PIN_CHANGE_NEW = 1;
64     private static final int PIN_CHANGE_REENTER = 2;
65     private static final int PIN_CHANGE_PUK = 3;
66     private int mPinChangeState;
67     private boolean mSkipOldPin;    // Indicates we know that we are PUK2 blocked.
68 
69     private static final String SKIP_OLD_PIN_KEY = "skip_old_pin_key";
70     private static final String PIN_CHANGE_STATE_KEY = "pin_change_state_key";
71     private static final String OLD_PIN_KEY = "old_pin_key";
72     private static final String NEW_PIN_KEY = "new_pin_key";
73     private static final String DIALOG_MESSAGE_KEY = "dialog_message_key";
74     private static final String DIALOG_PIN_ENTRY_KEY = "dialog_pin_entry_key";
75 
76     // size limits for the pin.
77     private static final int MIN_PIN_LENGTH = 4;
78     private static final int MAX_PIN_LENGTH = 8;
79 
80     /**
81      * Delegate to the respective handlers.
82      */
onPinEntered(EditPinPreference preference, boolean positiveResult)83     public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
84         if (preference == mButtonEnableFDN) {
85             toggleFDNEnable(positiveResult);
86         } else if (preference == mButtonChangePin2){
87             updatePINChangeState(positiveResult);
88         }
89     }
90 
91     /**
92      * Attempt to toggle FDN activation.
93      */
toggleFDNEnable(boolean positiveResult)94     private void toggleFDNEnable(boolean positiveResult) {
95         if (!positiveResult) {
96             return;
97         }
98 
99         // validate the pin first, before submitting it to the RIL for FDN enable.
100         String password = mButtonEnableFDN.getText();
101         if (validatePin (password, false)) {
102             // get the relevant data for the icc call
103             boolean isEnabled = mPhone.getIccCard().getIccFdnEnabled();
104             Message onComplete = mFDNHandler.obtainMessage(EVENT_PIN2_ENTRY_COMPLETE);
105 
106             // make fdn request
107             mPhone.getIccCard().setIccFdnEnabled(!isEnabled, password, onComplete);
108         } else {
109             // throw up error if the pin is invalid.
110             displayMessage(R.string.invalidPin2);
111         }
112 
113         mButtonEnableFDN.setText("");
114     }
115 
116     /**
117      * Attempt to change the pin.
118      */
updatePINChangeState(boolean positiveResult)119     private void updatePINChangeState(boolean positiveResult) {
120         if (!positiveResult) {
121             // reset the state on cancel, either to expect PUK2 or PIN2
122             if (!mSkipOldPin) {
123                 resetPinChangeState();
124             } else {
125                 resetPinChangeStateForPUK2();
126             }
127             return;
128         }
129 
130         // Progress through the dialog states, generally in this order:
131         //   1. Enter old pin
132         //   2. Enter new pin
133         //   3. Re-Enter new pin
134         // While handling any error conditions that may show up in between.
135         // Also handle the PUK2 entry, if it is requested.
136         //
137         // In general, if any invalid entries are made, the dialog re-
138         // appears with text to indicate what the issue is.
139         switch (mPinChangeState) {
140             case PIN_CHANGE_OLD:
141                 mOldPin = mButtonChangePin2.getText();
142                 mButtonChangePin2.setText("");
143                 // if the pin is not valid, display a message and reset the state.
144                 if (validatePin (mOldPin, false)) {
145                     mPinChangeState = PIN_CHANGE_NEW;
146                     displayPinChangeDialog();
147                 } else {
148                     displayPinChangeDialog(R.string.invalidPin2, true);
149                 }
150                 break;
151             case PIN_CHANGE_NEW:
152                 mNewPin = mButtonChangePin2.getText();
153                 mButtonChangePin2.setText("");
154                 // if the new pin is not valid, display a message and reset the state.
155                 if (validatePin (mNewPin, false)) {
156                     mPinChangeState = PIN_CHANGE_REENTER;
157                     displayPinChangeDialog();
158                 } else {
159                     displayPinChangeDialog(R.string.invalidPin2, true);
160                 }
161                 break;
162             case PIN_CHANGE_REENTER:
163                 // if the re-entered pin is not valid, display a message and reset the state.
164                 if (!mNewPin.equals(mButtonChangePin2.getText())) {
165                     mPinChangeState = PIN_CHANGE_NEW;
166                     mButtonChangePin2.setText("");
167                     displayPinChangeDialog(R.string.mismatchPin2, true);
168                 } else {
169                     // If the PIN is valid, then we either submit the change PIN request or
170                     // display the PUK2 dialog if we KNOW that we're PUK2 locked.
171                     mButtonChangePin2.setText("");
172                     if (!mSkipOldPin) {
173                         Message onComplete = mFDNHandler.obtainMessage(EVENT_PIN2_CHANGE_COMPLETE);
174                         mPhone.getIccCard().changeIccFdnPassword(mOldPin, mNewPin, onComplete);
175                     } else {
176                         mPinChangeState = PIN_CHANGE_PUK;
177                         displayPinChangeDialog();
178                     }
179                 }
180                 break;
181             case PIN_CHANGE_PUK: {
182                     // Doh! too many incorrect requests, PUK requested.
183                     // if the pin is not valid, display a message and reset the state.
184                     String puk2 = mButtonChangePin2.getText();
185                     mButtonChangePin2.setText("");
186                     // make sure that the puk is valid before submitting it.
187                     if (validatePin (puk2, true)) {
188                         Message onComplete = mFDNHandler.obtainMessage(EVENT_PIN2_CHANGE_COMPLETE);
189                         mPhone.getIccCard().supplyPuk2(puk2, mNewPin, onComplete);
190                     } else {
191                         displayPinChangeDialog(R.string.invalidPuk2, true);
192                     }
193                 }
194                 break;
195         }
196     }
197 
198     /**
199      * Handler for asynchronous replies from the sim.
200      */
201     private Handler mFDNHandler = new Handler() {
202         @Override
203         public void handleMessage(Message msg) {
204             switch (msg.what) {
205 
206                 // when we are enabling FDN, either we are unsuccessful and display
207                 // a toast, or just update the UI.
208                 case EVENT_PIN2_ENTRY_COMPLETE: {
209                         AsyncResult ar = (AsyncResult) msg.obj;
210                         if (ar.exception != null) {
211                             // see if PUK2 is requested and alert the user accordingly.
212                             CommandException ce = (CommandException) ar.exception;
213                             if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
214                                 // make sure we set the PUK2 state so that we can skip
215                                 // some redundant behaviour.
216                                 displayMessage(R.string.fdn_enable_puk2_requested);
217                                 resetPinChangeStateForPUK2();
218                             } else {
219                                 displayMessage(R.string.pin2_invalid);
220                             }
221                         }
222                         updateEnableFDN();
223                     }
224                     break;
225 
226                 // when changing the pin we need to pay attention to whether or not
227                 // the error requests a PUK (usually after too many incorrect tries)
228                 // Set the state accordingly.
229                 case EVENT_PIN2_CHANGE_COMPLETE: {
230                         AsyncResult ar = (AsyncResult) msg.obj;
231                         if (ar.exception != null) {
232                             CommandException ce = (CommandException) ar.exception;
233                             if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
234                                 // throw an alert dialog on the screen, displaying the
235                                 // request for a PUK2.  set the cancel listener to
236                                 // FdnSetting.onCancel().
237                                 AlertDialog a = new AlertDialog.Builder(FdnSetting.this)
238                                     .setMessage(R.string.puk2_requested)
239                                     .setCancelable(true)
240                                     .setOnCancelListener(FdnSetting.this)
241                                     .create();
242                                 a.getWindow().addFlags(
243                                         WindowManager.LayoutParams.FLAG_DIM_BEHIND);
244                                 a.show();
245                             } else {
246                                 // set the correct error message depending upon the state.
247                                 if (mPinChangeState == PIN_CHANGE_PUK) {
248                                     displayMessage(R.string.badPuk2);
249                                 } else {
250                                     displayMessage(R.string.badPin2);
251                                 }
252 
253                                 // Reset the state depending upon or knowledge of the PUK state.
254                                 if (!mSkipOldPin) {
255                                     resetPinChangeState();
256                                 } else {
257                                     resetPinChangeStateForPUK2();
258                                 }
259                             }
260                         } else {
261                             // reset to normal behaviour on successful change.
262                             displayMessage(R.string.pin2_changed);
263                             mSkipOldPin = false;
264                             resetPinChangeState();
265                         }
266                     }
267                     break;
268             }
269         }
270     };
271 
272     /**
273      * Cancel listener for the PUK2 request alert dialog.
274      */
onCancel(DialogInterface dialog)275     public void onCancel(DialogInterface dialog) {
276         // set the state of the preference and then display the dialog.
277         mPinChangeState = PIN_CHANGE_PUK;
278         displayPinChangeDialog(0, true);
279     }
280 
281     /**
282      * Display a toast for message, like the rest of the settings.
283      */
displayMessage(int strId)284     private final void displayMessage(int strId) {
285         Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT)
286             .show();
287     }
288 
289     /**
290      * The next two functions are for updating the message field on the dialog.
291      */
displayPinChangeDialog()292     private final void displayPinChangeDialog() {
293         displayPinChangeDialog(0, true);
294     }
295 
displayPinChangeDialog(int strId, boolean shouldDisplay)296     private final void displayPinChangeDialog(int strId, boolean shouldDisplay) {
297         int msgId;
298         switch (mPinChangeState) {
299             case PIN_CHANGE_OLD:
300                 msgId = R.string.oldPin2Label;
301                 break;
302             case PIN_CHANGE_NEW:
303                 msgId = R.string.newPin2Label;
304                 break;
305             case PIN_CHANGE_REENTER:
306                 msgId = R.string.confirmPin2Label;
307                 break;
308             case PIN_CHANGE_PUK:
309             default:
310                 msgId = R.string.label_puk2_code;
311                 break;
312         }
313 
314         // append the note / additional message, if needed.
315         if (strId != 0) {
316             mButtonChangePin2.setDialogMessage(getText(msgId) + "\n" + getText(strId));
317         } else {
318             mButtonChangePin2.setDialogMessage(msgId);
319         }
320 
321         // only display if requested.
322         if (shouldDisplay) {
323             mButtonChangePin2.showPinDialog();
324         }
325     }
326 
327     /**
328      * Reset the state of the pin change dialog.
329      */
resetPinChangeState()330     private final void resetPinChangeState() {
331         mPinChangeState = PIN_CHANGE_OLD;
332         displayPinChangeDialog(0, false);
333         mOldPin = mNewPin = "";
334     }
335 
336     /**
337      * Reset the state of the pin change dialog solely for PUK2 use.
338      */
resetPinChangeStateForPUK2()339     private final void resetPinChangeStateForPUK2() {
340         mPinChangeState = PIN_CHANGE_NEW;
341         displayPinChangeDialog(0, false);
342         mOldPin = mNewPin = "";
343         mSkipOldPin = true;
344     }
345 
346     /**
347      * Validate the pin entry.
348      *
349      * @param pin This is the pin to validate
350      * @param isPuk Boolean indicating whether we are to treat
351      * the pin input as a puk.
352      */
validatePin(String pin, boolean isPUK)353     private boolean validatePin(String pin, boolean isPUK) {
354 
355         // for pin, we have 4-8 numbers, or puk, we use only 8.
356         int pinMinimum = isPUK ? MAX_PIN_LENGTH : MIN_PIN_LENGTH;
357 
358         // check validity
359         if (pin == null || pin.length() < pinMinimum || pin.length() > MAX_PIN_LENGTH) {
360             return false;
361         } else {
362             return true;
363         }
364     }
365 
366     /**
367      * Reflect the updated FDN state in the UI.
368      */
updateEnableFDN()369     private void updateEnableFDN() {
370         if (mPhone.getIccCard().getIccFdnEnabled()) {
371             mButtonEnableFDN.setTitle(R.string.enable_fdn_ok);
372             mButtonEnableFDN.setSummary(R.string.fdn_enabled);
373             mButtonEnableFDN.setDialogTitle(R.string.disable_fdn);
374         } else {
375             mButtonEnableFDN.setTitle(R.string.disable_fdn_ok);
376             mButtonEnableFDN.setSummary(R.string.fdn_disabled);
377             mButtonEnableFDN.setDialogTitle(R.string.enable_fdn);
378         }
379     }
380 
381     @Override
onCreate(Bundle icicle)382     protected void onCreate(Bundle icicle) {
383         super.onCreate(icicle);
384 
385         addPreferencesFromResource(R.xml.fdn_setting);
386 
387         mPhone = PhoneFactory.getDefaultPhone();
388 
389         //get UI object references
390         PreferenceScreen prefSet = getPreferenceScreen();
391         mButtonEnableFDN = (EditPinPreference) prefSet.findPreference(BUTTON_FDN_ENABLE_KEY);
392         mButtonChangePin2 = (EditPinPreference) prefSet.findPreference(BUTTON_CHANGE_PIN2_KEY);
393 
394         //assign click listener and update state
395         mButtonEnableFDN.setOnPinEnteredListener(this);
396         updateEnableFDN();
397 
398         mButtonChangePin2.setOnPinEnteredListener(this);
399 
400         // Only reset the pin change dialog if we're not in the middle of changing it.
401         if (icicle == null) {
402             resetPinChangeState();
403         } else {
404             mSkipOldPin = icicle.getBoolean(SKIP_OLD_PIN_KEY);
405             mPinChangeState = icicle.getInt(PIN_CHANGE_STATE_KEY);
406             mOldPin = icicle.getString(OLD_PIN_KEY);
407             mNewPin = icicle.getString(NEW_PIN_KEY);
408             mButtonChangePin2.setDialogMessage(icicle.getString(DIALOG_MESSAGE_KEY));
409             mButtonChangePin2.setText(icicle.getString(DIALOG_PIN_ENTRY_KEY));
410         }
411     }
412 
413     @Override
onResume()414     protected void onResume() {
415         super.onResume();
416         mPhone = PhoneFactory.getDefaultPhone();
417         updateEnableFDN();
418     }
419 
420     /**
421      * Save the state of the pin change.
422      */
423     @Override
onSaveInstanceState(Bundle out)424     protected void onSaveInstanceState(Bundle out) {
425         super.onSaveInstanceState(out);
426         out.putBoolean(SKIP_OLD_PIN_KEY, mSkipOldPin);
427         out.putInt(PIN_CHANGE_STATE_KEY, mPinChangeState);
428         out.putString(OLD_PIN_KEY, mOldPin);
429         out.putString(NEW_PIN_KEY, mNewPin);
430         out.putString(DIALOG_MESSAGE_KEY, mButtonChangePin2.getDialogMessage().toString());
431         out.putString(DIALOG_PIN_ENTRY_KEY, mButtonChangePin2.getText());
432     }
433 }
434 
435