Misc phone app code cleanup.
[android/platform/packages/apps/Phone.git] / src / com / android / phone / CallFeaturesSetting.java
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.app.Dialog;
21 import android.app.ProgressDialog;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.database.Cursor;
25 import android.os.AsyncResult;
26 import android.os.Bundle;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.preference.CheckBoxPreference;
30 import android.preference.ListPreference;
31 import android.preference.Preference;
32 import android.preference.PreferenceActivity;
33 import android.preference.PreferenceScreen;
34 import android.provider.Settings;
35 import android.provider.Contacts.PhonesColumns;
36 import android.telephony.PhoneNumberUtils;
37 import android.telephony.ServiceState;
38 import android.text.TextUtils;
39 import android.util.Log;
40 import android.view.WindowManager;
41
42 import com.android.internal.telephony.CallForwardInfo;
43 import com.android.internal.telephony.CommandsInterface;
44 import com.android.internal.telephony.Phone;
45 import com.android.internal.telephony.PhoneFactory;
46 import com.android.internal.telephony.cdma.TtyIntent;
47 import android.content.Context;
48
49 public class CallFeaturesSetting extends PreferenceActivity
50         implements DialogInterface.OnClickListener,
51         Preference.OnPreferenceChangeListener,
52         EditPhoneNumberPreference.OnDialogClosedListener,
53         EditPhoneNumberPreference.GetDefaultNumberListener{
54
55     // intent action for this activity.
56     public static final String ACTION_ADD_VOICEMAIL =
57         "com.android.phone.CallFeaturesSetting.ADD_VOICEMAIL";
58
59     // debug data
60     private static final String LOG_TAG = "CallFeaturesSetting";
61     private static final boolean DBG = false;
62
63     // string contants
64     private static final String NUM_PROJECTION[] = {PhonesColumns.NUMBER};
65     private static final String SRC_TAGS[]       = {"{0}"};
66
67     // String keys for preference lookup
68     private static final String BUTTON_CLIR_KEY  = "button_clir_key";
69     private static final String BUTTON_CW_KEY    = "button_cw_key";
70     private static final String BUTTON_CFU_KEY   = "button_cfu_key";
71     private static final String BUTTON_CFB_KEY   = "button_cfb_key";
72     private static final String BUTTON_CFNRY_KEY = "button_cfnry_key";
73     private static final String BUTTON_CFNRC_KEY = "button_cfnrc_key";
74     private static final String BUTTON_VOICEMAIL_KEY = "button_voicemail_key";
75     private static final String BUTTON_FDN_KEY   = "button_fdn_key";
76
77     // used to store the state of expanded preferences
78     private static final String BUTTON_GSM_MORE_EXPAND_KEY = "button_gsm_more_expand_key";
79     private static final String BUTTON_CDMA_MORE_EXPAND_KEY = "button_cdma_more_expand_key";
80
81     private static final String BUTTON_CF_EXPAND_KEY = "button_cf_expand_key";
82     private static final String SUMMARY_CFU_KEY   = "summary_cfu_key";
83     private static final String SUMMARY_CFB_KEY   = "summary_cfb_key";
84     private static final String SUMMARY_CFNRY_KEY = "summary_cfnry_key";
85     private static final String SUMMARY_CFNRC_KEY = "summary_cfnrc_key";
86
87     private static final String APP_STATE_KEY     = "app_state_key";
88     private static final String DISPLAY_MODE_KEY  = "display_mode_key";
89
90     private static final String BUTTON_TTY_KEY = "button_tty_mode_key";
91     private static final String BUTTON_VP_KEY = "button_voice_privacy_key";
92     private static final String BUTTON_DS_KEY = "dtmf_settings";
93
94     private Intent mContactListIntent;
95     private Intent mFDNSettingIntent;
96
97     // events
98     private static final int EVENT_SERVICE_STATE_CHANGED = 100;
99     private static final int EVENT_CLIR_EXECUTED         = 200;
100     private static final int EVENT_CW_EXECUTED           = 300;
101     private static final int EVENT_CF_EXECUTED           = 400;
102     /** Event for Async voicemail change call */
103     private static final int EVENT_VOICEMAIL_CHANGED     = 500;
104     /** track the query cancel event. */
105     private static final int EVENT_INITAL_QUERY_CANCELED = 600;
106     /** Event for TTY mode change */
107     private static final int EVENT_TTY_EXECUTED          = 700;
108     private static final int EVENT_TTY_MODE_SET          = 800;
109     private static final int EVENT_ENHANCED_VP_EXECUTED  = 1000;
110
111     // preferred TTY mode
112     // 0 = disabled
113     // 1 = full mode
114     // 2 = HCO mode
115     // 3 = VCO mode
116     static final int preferredTtyMode = 0;
117
118     // preferred VoicePrivacy mode
119     // 0 = disabled
120     // 1 = enabled
121     static final int preferredVPMode = 1;
122
123     // Dtmf tone types
124     static final int DTMF_TONE_TYPE_NORMAL = 0;
125     static final int DTMF_TONE_TYPE_LONG   = 1;
126
127     // preferred DTMF Tones mode
128     static final int preferredDtmfMode = DTMF_TONE_TYPE_NORMAL;
129
130
131     /** Handle to voicemail pref */
132     private static final int VOICEMAIL_PREF_ID = CommandsInterface.CF_REASON_NOT_REACHABLE + 1;
133
134     private Phone mPhone;
135
136     private static final int BUSY_DIALOG = 100;
137     private static final int EXCEPTION_ERROR = 200;
138     private static final int RESPONSE_ERROR = 300;
139     private static final int VM_NOCHANGE_ERROR = 400;
140     private static final int VM_RESPONSE_ERROR = 500;
141
142     /** used to track errors with the radio off. */
143     private static final int RADIO_OFF_ERROR = 800;
144     private static final int INITIAL_BUSY_DIALOG = 900;
145
146     // dialog identifiers for voicemail
147     private static final int VOICEMAIL_DIALOG_CONFIRM = 600;
148     private static final int VOICEMAIL_DIALOG_PROGRESS = 700;
149
150     // status message sent back from handlers
151     //  handleGetCLIRMessage
152     //  handleGetCWMessage
153     //  handleGetCFMessage
154     private static final int MSG_OK = 100;
155     private static final int MSG_EXCEPTION = 200;
156     private static final int MSG_UNEXPECTED_RESPONSE = 300;
157     // special statuses for voicemail controls.
158     private static final int MSG_VM_EXCEPTION = 400;
159     private static final int MSG_VM_BUSY = 500;
160     private static final int MSG_VM_OK = 600;
161     private static final int MSG_VM_NOCHANGE = 700;
162     private static final int MSG_RADIO_OFF = 800;
163
164     // application states including network error state.
165     // this includes seperate state for the inital query, which is cancelable.
166     private enum AppState {
167         INPUT_READY,
168         DIALOG_OPEN,
169         WAITING_NUMBER_SELECT,
170         BUSY_NETWORK_CONNECT,
171         NETWORK_ERROR,
172         INITIAL_QUERY
173     };
174     private AppState mAppState;
175
176     /** Additional state tracking to handle expanded views (lazy queries)*/
177     private static final int DISP_MODE_MAIN = -1;
178     private static final int DISP_MODE_CF = -2;
179     private static final int DISP_MODE_MORE = -3;
180     private int mDisplayMode;
181     private boolean mCFDataStale = true;
182     private boolean mMoreDataStale = true;
183     private boolean mIsBusyDialogAvailable = false;
184
185     // toggle buttons
186     private PreferenceScreen mSubMenuFDNSettings;
187     private ListPreference mButtonCLIR;
188     private CheckBoxPreference mButtonCW;
189     private EditPhoneNumberPreference mButtonCFU;
190     private EditPhoneNumberPreference mButtonCFB;
191     private EditPhoneNumberPreference mButtonCFNRy;
192     private EditPhoneNumberPreference mButtonCFNRc;
193     private EditPhoneNumberPreference mSubMenuVoicemailSettings;
194     private PreferenceScreen mButtonCFExpand;
195     private PreferenceScreen mButtonGSMMoreExpand;
196     private PreferenceScreen mButtonCDMAMoreExpand;
197     private CheckBoxPreference mButtonVoicePrivacy;
198     private ListPreference mButtonTTY;
199     private ListPreference mButtonDS;
200
201     // cf number strings
202     private String mDialingNumCFU;
203     private String mDialingNumCFB;
204     private String mDialingNumCFNRy;
205     private String mDialingNumCFNRc;
206     /** string to hold old voicemail number as it is being updated. */
207     private String mOldVmNumber;
208
209
210     /*
211      * Click Listeners, handle click based on objects attached to UI.
212      */
213
214     // Click listener for all toggle events
215     @Override
216     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
217         if (mAppState != AppState.INPUT_READY) {
218             if (DBG) {
219                 log("onPreferencesHierarchyClick: preference request denied, currently busy.");
220             }
221             return false;
222         }
223
224         if (DBG) log("onPreferencesHierarchyClick: request preference click.");
225
226         AppState nextState = AppState.INPUT_READY;
227
228         if (preference == mButtonCW) {
229             handleCWClickRequest(mButtonCW.isChecked());
230             nextState = AppState.BUSY_NETWORK_CONNECT;
231
232         } else if (preference == mButtonCLIR) {
233             // let the normal listpreference UI take care of this.
234             return false;
235
236         } else if ((preference instanceof EditPhoneNumberPreference) &&
237                 ((preference == mButtonCFU) || (preference == mButtonCFB) ||
238                 (preference == mButtonCFNRy) || (preference == mButtonCFNRc) ||
239                 (preference == mSubMenuVoicemailSettings))) {
240             nextState = AppState.DIALOG_OPEN;
241         } else if (preference == mSubMenuFDNSettings) {
242             // let the intent handler from the caller take care of the
243             // navigation to the FDN screen.
244             return false;
245
246         /** perform the requested expansion, and query the network.*/
247         } else if (preference == mButtonCFExpand){
248             setDisplayMode(DISP_MODE_CF);
249             return true;
250         } else if (preference == mButtonGSMMoreExpand){
251             // TODO - should have handler for mButtonCDMAMoreExpand?
252             setDisplayMode(DISP_MODE_MORE);
253         } else if (preference == mButtonVoicePrivacy) {
254             handleVoicePrivacyClickRequest(mButtonVoicePrivacy.isChecked());
255         } else if (preference == mButtonTTY) {
256             //displays the value taken from the Settings.System
257             int settingsTtyMode = android.provider.Settings.Secure.getInt(
258                     mPhone.getContext().getContentResolver(),
259                     android.provider.Settings.Secure.PREFERRED_TTY_MODE ,
260                     preferredTtyMode);
261             mButtonTTY.setValue(Integer.toString(settingsTtyMode));
262             return true;
263         } else if (preference == mButtonDS) {
264             // Let the normal listpreference UI take care of this
265             return false;
266         }
267
268         if (nextState != AppState.INPUT_READY) {
269             setAppState(nextState);
270             return true;
271         }
272
273         return false;
274     }
275
276     /**
277      * Implemented to support onPreferenceChangeListener to look for preference
278      * changes specifically on CLIR.
279      *
280      * @param preference is the preference to be changed, should be mButtonCLIR.
281      * @param objValue should be the value of the selection, NOT its localized
282      * display value.
283      */
284     public boolean onPreferenceChange(Preference preference, Object objValue) {
285         if (preference == mButtonCLIR) {
286             // send the command and update state.
287             handleCLIRClickRequest(mButtonCLIR.findIndexOfValue((String) objValue));
288             setAppState(AppState.BUSY_NETWORK_CONNECT);
289         } else if (preference == mButtonTTY) {
290             // send the command and update state.
291             handleTTYClickRequest(preference, objValue);
292         } else if (preference == mButtonDS) {
293             int index = mButtonDS.findIndexOfValue((String) objValue);
294             Settings.System.putInt(mPhone.getContext().getContentResolver(),
295                     Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index);
296         }
297         // always let the preference setting proceed.
298         return true;
299     }
300
301
302     /**
303      * Perform the query request for the expanded items upon user request.
304      */
305     public void setDisplayMode(int displayMode) {
306         mDisplayMode = displayMode;
307
308         // look for the data if it is considered stale.
309         if ((mCFDataStale && (displayMode == DISP_MODE_CF)) ||
310                 (mMoreDataStale && (displayMode == DISP_MODE_MORE))){
311             if (DBG) log("setDisplayMode: performing requested expansion.");
312
313             // check for CDMA, if so just open without querying
314             if ( mPhone.getPhoneName().equals("CDMA") ) {
315                 setAppState(AppState.INPUT_READY);
316             } else {
317                 // If airplane mode is on, do not bother querying.
318                 if (Settings.System.getInt(getContentResolver(),
319                         Settings.System.AIRPLANE_MODE_ON, 0) <= 0 ) {
320                     // query state if radio is available
321                     //  if its out of service, just wait for the radio to be ready
322                     //  if its neither of these states, throw up an error.
323                     setAppState(AppState.INITIAL_QUERY);
324
325                     int radioState = mPhone.getServiceState().getState();
326
327                     if (radioState == ServiceState.STATE_IN_SERVICE) {
328                         // Query ONLY what we are currently expanding.
329                         if (displayMode == DISP_MODE_CF) {
330                             queryAllCFOptions();
331                         } else {
332                             queryMoreOptions();
333                         }
334                     } else if (radioState == ServiceState.STATE_POWER_OFF){
335                         if (DBG) log("onCreate: radio not ready, waiting for signal.");
336                         mPhone.registerForServiceStateChanged(mNetworkServiceHandler,
337                                 EVENT_SERVICE_STATE_CHANGED, null);
338                     } else {
339                         setAppState(AppState.NETWORK_ERROR, MSG_EXCEPTION);
340                     }
341                 } else {
342                     if (DBG) log("setDisplayMode: radio is off!");
343                     setAppState(AppState.NETWORK_ERROR, MSG_RADIO_OFF);
344                 }
345             }
346         }
347     }
348
349     // Preference click listener invoked on OnDialogClosed for EditPhoneNumberPreference.
350     public void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked) {
351         if (mAppState != AppState.DIALOG_OPEN) {
352             if (DBG) {
353                 log("onPreferenceClick: preference request denied, currently busy.");
354             }
355             return;
356         } else if (buttonClicked == DialogInterface.BUTTON2) {
357             // Button2 is the cancel button.
358             setAppState (AppState.INPUT_READY);
359             return;
360         }
361
362         if (DBG) log("onPreferenceClick: request preference click on dialog close.");
363
364         AppState nextState = AppState.INPUT_READY;
365
366         if (preference instanceof EditPhoneNumberPreference) {
367             EditPhoneNumberPreference epn = preference;
368
369             if (epn == mSubMenuVoicemailSettings) {
370                 handleVMBtnClickRequest();
371
372             } else {
373                 int reason = 0;
374                 int time = 0;
375                 String number = "";
376                 // We use CommandsInterface.CF_ACTION_REGISTRATION for both the Enable
377                 // and Update (Button1) functions.
378                 int action = (epn.isToggled() || (buttonClicked == DialogInterface.BUTTON1)) ?
379                         CommandsInterface.CF_ACTION_REGISTRATION :
380                         CommandsInterface.CF_ACTION_DISABLE;
381
382                 // The formatted string seems to be giving the MMI codes some problems,
383                 // so we strip the formatting first before sending the number.
384                 number = PhoneNumberUtils.stripSeparators((epn.getPhoneNumber()));
385                 if (epn == mButtonCFU) {
386                     nextState = AppState.BUSY_NETWORK_CONNECT;
387                     reason = CommandsInterface.CF_REASON_UNCONDITIONAL;
388                     mDialingNumCFU = number;
389                 } else if (epn == mButtonCFB) {
390                     nextState = AppState.BUSY_NETWORK_CONNECT;
391                     reason = CommandsInterface.CF_REASON_BUSY;
392                     mDialingNumCFB = number;
393                 } else if (epn == mButtonCFNRy) {
394                     nextState = AppState.BUSY_NETWORK_CONNECT;
395                     reason = CommandsInterface.CF_REASON_NO_REPLY;
396                     time = 20;
397                     mDialingNumCFNRy = number;
398                 } else if (epn == mButtonCFNRc) {
399                     nextState = AppState.BUSY_NETWORK_CONNECT;
400                     reason = CommandsInterface.CF_REASON_NOT_REACHABLE;
401                     mDialingNumCFNRc = number;
402                 }
403
404                 if (nextState == AppState.BUSY_NETWORK_CONNECT) {
405                     handleCFBtnClickRequest(action, reason, time, number);
406                 }
407
408                 if (nextState != AppState.DIALOG_OPEN) {
409                     setAppState(nextState);
410                 }
411             }
412         }
413     }
414
415     /**
416      * Implemented for EditPhoneNumberPreference.GetDefaultNumberListener.
417      * This method set the default values for the various
418      * EditPhoneNumberPreference dialogs.
419      */
420     public String onGetDefaultNumber(EditPhoneNumberPreference preference) {
421         if (preference == mSubMenuVoicemailSettings) {
422             // update the voicemail number field, which takes care of the
423             // mSubMenuVoicemailSettings itself, so we should return null.
424             if (DBG) log("updating default for voicemail dialog");
425             updateVoiceNumberField();
426             return null;
427         }
428
429         String vmDisplay = mPhone.getVoiceMailNumber();
430         if (TextUtils.isEmpty(vmDisplay)) {
431             // if there is no voicemail number, we just return null to
432             // indicate no contribution.
433             return null;
434         }
435
436         // Return the voicemail number prepended with "VM: "
437         if (DBG) log("updating default for call forwarding dialogs");
438         return getString(R.string.voicemail_abbreviated) + " " + vmDisplay;
439     }
440
441
442     // override the startsubactivity call to make changes in state consistent.
443     @Override
444     public void startActivityForResult(Intent intent, int requestCode) {
445         if (requestCode == -1) {
446             // this is an intent requested from the preference framework.
447             super.startActivityForResult(intent, requestCode);
448             return;
449         }
450
451         if (mAppState != AppState.DIALOG_OPEN) {
452             if (DBG) {
453                 log("startSubActivity: dialog start activity request denied, currently busy.");
454             }
455             return;
456         }
457
458         if (DBG) log("startSubActivity: starting requested subactivity");
459
460         super.startActivityForResult(intent, requestCode);
461
462         setAppState (AppState.WAITING_NUMBER_SELECT);
463     }
464
465     // asynchronous result call after contacts are selected.
466     @Override
467     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
468         // there are cases where the contact picker may end up sending us more than one
469         // request.  We want to ignore the request if we're not in the correct state.
470         if (mAppState != AppState.WAITING_NUMBER_SELECT) {
471             if (DBG) log("onActivityResult: wrong state, ignoring message from contact picker.");
472             return;
473         } else {
474             setAppState(AppState.DIALOG_OPEN);
475         }
476
477         if (resultCode != RESULT_OK) {
478             if (DBG) log("onActivityResult: contact picker result not OK.");
479             return;
480         }
481
482         Cursor cursor = getContentResolver().query(data.getData(),
483                 NUM_PROJECTION, null, null, null);
484         if ((cursor == null) || (!cursor.moveToFirst())) {
485             if (DBG) log("onActivityResult: bad contact data, no results found.");
486             return;
487         }
488
489         switch (requestCode) {
490             case CommandsInterface.CF_REASON_UNCONDITIONAL:
491                 mButtonCFU.onPickActivityResult(cursor.getString(0));
492                 break;
493             case CommandsInterface.CF_REASON_BUSY:
494                 mButtonCFB.onPickActivityResult(cursor.getString(0));
495                 break;
496             case CommandsInterface.CF_REASON_NO_REPLY:
497                 mButtonCFNRy.onPickActivityResult(cursor.getString(0));
498                 break;
499             case CommandsInterface.CF_REASON_NOT_REACHABLE:
500                 mButtonCFNRc.onPickActivityResult(cursor.getString(0));
501                 break;
502             case VOICEMAIL_PREF_ID:
503                 mSubMenuVoicemailSettings.onPickActivityResult(cursor.getString(0));
504                 break;
505             default:
506                 // TODO: may need exception here.
507         }
508
509     }
510
511     // CLIR object
512     private void handleCLIRClickRequest(int i) {
513         if (DBG) log("handleCLIRClickRequest: requesting set Call Line Id Restriction (CLIR) to " +
514                 (i == CommandsInterface.CLIR_INVOCATION ? "ENABLE" :
515                     (i == CommandsInterface.CLIR_SUPPRESSION ? "DISABLE" : "NETWORK DEFAULT")));
516         mPhone.setOutgoingCallerIdDisplay(i,
517                 Message.obtain(mSetOptionComplete, EVENT_CLIR_EXECUTED));
518     }
519
520     // CW object
521     private void handleCWClickRequest(boolean b) {
522         if (DBG) log("handleCWClickRequest: requesting set call waiting enable (CW) to" +
523                 Boolean.toString(b));
524         mPhone.setCallWaiting(b, Message.obtain(mSetOptionComplete, EVENT_CW_EXECUTED));
525     }
526
527     // CF Button objects
528     private void handleCFBtnClickRequest(int action, int reason, int time, String number) {
529         if (DBG) log("handleCFBtnClickRequest: requesting set call forwarding (CF) " +
530                 Integer.toString(reason) + " to " + Integer.toString(action) + " with number " +
531                 number);
532         mPhone.setCallForwardingOption(action,
533                 reason,
534                 number,
535                 time,
536                 Message.obtain(mSetOptionComplete, EVENT_CF_EXECUTED, reason, 0));
537     }
538
539     // Voicemail button logic
540     private void handleVMBtnClickRequest() {
541         // normally called on the dialog close.
542
543         // Since we're stripping the formatting out on the getPhoneNumber()
544         // call now, we won't need to do so here anymore.
545         String newVMNumber = mSubMenuVoicemailSettings.getPhoneNumber();
546
547         // empty vm number == clearing the vm number ?
548         if (newVMNumber == null) {
549             newVMNumber = "";
550         }
551
552         //throw a warning if they are the same.
553         if (newVMNumber.equals(mOldVmNumber)) {
554             setAppState(AppState.INPUT_READY, MSG_VM_NOCHANGE);
555             return;
556         }
557
558         // otherwise, set it.
559         setAppState (AppState.BUSY_NETWORK_CONNECT, MSG_VM_BUSY);
560         if (DBG) log("save voicemail #: " + newVMNumber);
561         mPhone.setVoiceMailNumber(
562                 mPhone.getVoiceMailAlphaTag().toString(),
563                 newVMNumber,
564                 Message.obtain(mSetOptionComplete, EVENT_VOICEMAIL_CHANGED));
565     }
566
567     /*
568      * Callback to handle option update completions
569      */
570
571     // **Callback on option setting when complete.
572     private Handler mSetOptionComplete = new Handler() {
573         @Override
574         public void handleMessage(Message msg) {
575             // query to make sure we're looking at the same data as that in the network.
576             switch (msg.what) {
577                 case EVENT_CLIR_EXECUTED:
578                     handleSetCLIRMessage();
579                     break;
580                 case EVENT_CW_EXECUTED:
581                     handleSetCWMessage();
582                     break;
583                 case EVENT_CF_EXECUTED:
584                     handleSetCFMessage(msg.arg1, (AsyncResult) msg.obj);
585                     break;
586                 case EVENT_VOICEMAIL_CHANGED:
587                     handleSetVMMessage((AsyncResult) msg.obj);
588                     break;
589                 default:
590                     // TODO: should never reach this, may want to throw exception
591             }
592         }
593     };
594
595     // CLIR Object
596     private void handleSetCLIRMessage() {
597         if (DBG) {
598             log("handleSetCLIRMessage: set CLIR request complete, reading value from network.");
599         }
600         mPhone.getOutgoingCallerIdDisplay(Message.obtain(mGetOptionComplete, EVENT_CLIR_EXECUTED));
601     }
602
603     // CW Object
604     private void handleSetCWMessage() {
605         if (DBG) {
606             log("handleSetCWMessage: set CW request complete, reading value back from network.");
607         }
608         mPhone.getCallWaiting(Message.obtain(mGetOptionComplete, EVENT_CW_EXECUTED));
609     }
610
611     // CF Objects
612     private void handleSetCFMessage(int reason, AsyncResult r) {
613         if (DBG) {
614             log("handleSetCFMessage: set CF request complete, reading value back from network.");
615         }
616
617         // handle the exception in the set function's async result by
618         // propagating it to the getCallForwarding function.  This is
619         // so that we can display the error AFTER the setting has gone
620         // through the standard (set/get) cycle.
621         mPhone.getCallForwardingOption(reason,
622                 Message.obtain(mGetOptionComplete, EVENT_CF_EXECUTED, reason, 0, r.exception));
623     }
624
625     // Voicemail Object
626     private void handleSetVMMessage(AsyncResult ar) {
627         if (DBG) {
628             log("handleSetVMMessage: set VM request complete");
629         }
630         if (ar.exception == null) {
631             if (DBG) log("change VM success!");
632             setAppState(AppState.INPUT_READY, MSG_VM_OK);
633         } else {
634             // TODO: may want to check the exception and branch on it.
635             if (DBG) log("change VM failed!");
636             setAppState(AppState.NETWORK_ERROR, MSG_VM_EXCEPTION);
637         }
638         updateVoiceNumberField();
639     }
640
641     /*
642      * Callback to handle query completions
643      */
644
645     // **Callback on option getting when complete.
646     private Handler mGetOptionComplete = new Handler() {
647         @Override
648         public void handleMessage(Message msg) {
649             boolean bHandled = false;
650             int status = MSG_OK;
651             switch (msg.what) {
652                 case EVENT_CLIR_EXECUTED:
653                     status = handleGetCLIRMessage((AsyncResult) msg.obj);
654                     bHandled = true;
655                     break;
656                 case EVENT_CW_EXECUTED:
657                     status = handleGetCWMessage((AsyncResult) msg.obj);
658                     bHandled = true;
659                     break;
660                 case EVENT_CF_EXECUTED:
661                     status = handleGetCFMessage((AsyncResult) msg.obj, msg.arg1);
662                     bHandled = true;
663                     break;
664                 default:
665                     // TODO: should never reach this, may want to throw exception
666             }
667             if (status != MSG_OK) {
668                 setAppState(AppState.NETWORK_ERROR, status);
669             } else if (bHandled) {
670                 setAppState(AppState.INPUT_READY);
671             }
672         }
673     };
674
675     // CLIR Object
676     private int handleGetCLIRMessage(AsyncResult ar) {
677         // done with query, display the new settings.
678         if (ar.exception != null) {
679             if (DBG) log("handleGetCLIRMessage: Error getting CLIR enable state.");
680             return MSG_EXCEPTION;
681         } else {
682             int clirArray[] = (int[]) ar.result;
683             if (clirArray.length != 2) {
684                 if (DBG) log("handleGetCLIRMessage: Error getting CLIR state, unexpected value.");
685                 return MSG_UNEXPECTED_RESPONSE;
686             } else {
687                 if (DBG) log("handleGetCLIRMessage: CLIR enable state successfully queried.");
688                 syncCLIRUIState(clirArray);
689             }
690         }
691         return MSG_OK;
692     }
693
694     // CW Object
695     private int handleGetCWMessage(AsyncResult ar) {
696         if (ar.exception != null) {
697             if (DBG) log("handleGetCWMessage: Error getting CW enable state.");
698             return MSG_EXCEPTION;
699         } else {
700             if (DBG) log("handleGetCWMessage: CW enable state successfully queried.");
701             syncCWState((int[]) ar.result);
702         }
703         return MSG_OK;
704     }
705
706     // VP Object
707     private int handleGetVPMessage(AsyncResult ar, int voicePrivacyMode) {
708         if (ar.exception != null) {
709             if (DBG) log("handleGetVPMessage: Error getting VP enable state.");
710             return MSG_EXCEPTION;
711         } else {
712             Log.d(LOG_TAG, "voicePrivacyMode = " + voicePrivacyMode);
713             syncVPState((int[]) ar.result);
714         }
715
716         return MSG_OK;
717     }
718
719     // CF Object
720     private int handleGetCFMessage(AsyncResult ar, int reason) {
721         // done with query, display the new settings.
722         if (ar.exception != null) {
723             if (DBG) log("handleGetCFMessage: Error getting CF enable state.");
724             return MSG_EXCEPTION;
725         } else if (ar.userObj instanceof Throwable) {
726             // TODO: I don't think it makes sense to throw the error up to
727             // the user, but this may be reconsidered.  For now, just log
728             // the specific error and throw up a generic error.
729             if (DBG) log("handleGetCFMessage: Error during set call, reason: " + reason +
730                     " exception: " + ((Throwable) ar.userObj).toString());
731             return MSG_UNEXPECTED_RESPONSE;
732         } else {
733             CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
734             if (cfInfoArray.length == 0) {
735                 if (DBG) log("handleGetCFMessage: Error getting CF state, unexpected value.");
736                 return MSG_UNEXPECTED_RESPONSE;
737             } else {
738                 // TODO: look through the information for the voice data
739                 // in reality, we should probably take the other service
740                 // classes into account, but this may be more than we
741                 // want to expose to the user.
742                 for (int i = 0, length = cfInfoArray.length; i < length; i++) {
743                     if ((CommandsInterface.SERVICE_CLASS_VOICE &
744                             cfInfoArray[i].serviceClass) != 0) {
745                         if (DBG) {
746                             log("handleGetCFMessage: CF state successfully queried for reason " +
747                                 Integer.toBinaryString(reason));
748                         }
749                         syncCFUIState(reason, cfInfoArray[i]);
750                         break;
751                     }
752                 }
753             }
754         }
755         return MSG_OK;
756     }
757
758     /*
759      * Methods used to sync UI state with that of the network
760      */
761
762     // set the state of the UI based on CW State
763     private void syncCWState(int cwArray[]) {
764         if (DBG) log("syncCWState: Setting UI state consistent with CW enable state of " +
765                 ((cwArray[0] == 1) ? "ENABLED" : "DISABLED"));
766         mButtonCW.setChecked(cwArray[0] == 1);
767     }
768
769     /**
770      * The logic in this method is based upon the code in {@link CommandsInterface#getCLIR()}.
771      *
772      * @param clirArgs is the int[2] retrieved from the getCLIR response, please refer to
773      * the link above more more details.
774      */
775     private void syncCLIRUIState(int clirArgs[]) {
776         if (DBG) log("syncCLIRUIState: Setting UI state consistent with CLIR.");
777
778         // enable if the setting is valid.
779         final boolean enabled = clirArgs[1] == 1 || clirArgs[1] == 3 || clirArgs[1] == 4;
780         mButtonCLIR.setEnabled(enabled);
781
782         // set the value of the preference based upon the clirArgs.
783         int value = CommandsInterface.CLIR_DEFAULT;
784         switch (clirArgs[1]) {
785             case 1: // Permanently provisioned
786             case 3: // Temporary presentation disallowed
787             case 4: // Temporary presentation allowed
788                 switch (clirArgs[0]) {
789                     case 1: // CLIR invoked
790                         value = CommandsInterface.CLIR_INVOCATION;
791                         break;
792                     case 2: // CLIR suppressed
793                         value = CommandsInterface.CLIR_SUPPRESSION;
794                         break;
795                     case 0: // Network default
796                     default:
797                         value = CommandsInterface.CLIR_DEFAULT;
798                         break;
799                 }
800                 break;
801             case 0: // Not Provisioned
802             case 2: // Unknown (network error, etc)
803             default:
804                 value = CommandsInterface.CLIR_DEFAULT;
805                 break;
806         }
807         setButtonCLIRValue(value);
808     }
809
810     /**
811      * Helper function to set both the value and the summary of the CLIR preference.
812      */
813     private void setButtonCLIRValue (int value) {
814
815         if (mButtonCLIR == null) {
816             return;
817         }
818
819         // first, set the value.
820         mButtonCLIR.setValueIndex(value);
821
822         // set the string summary to reflect the value
823         int summary = R.string.sum_default_caller_id;
824         switch (value) {
825             case CommandsInterface.CLIR_SUPPRESSION:
826                 summary = R.string.sum_show_caller_id;
827                 break;
828             case CommandsInterface.CLIR_INVOCATION:
829                 summary = R.string.sum_hide_caller_id;
830                 break;
831             case CommandsInterface.CLIR_DEFAULT:
832                 summary = R.string.sum_default_caller_id;
833                 break;
834         }
835         mButtonCLIR.setSummary(summary);
836     }
837
838     // called by syncCFUIState to do repetitive changes to UI button state.
839     private void adjustCFbuttonState(EditPhoneNumberPreference epn,
840             boolean isActive, int template, String number) {
841
842         if (epn == null) {
843             return;
844         }
845
846         CharSequence summaryOn = "";
847
848         if (isActive) {
849             if (number != null) {
850                 String values[] = {number};
851                 summaryOn = TextUtils.replace(getText(template), SRC_TAGS, values);
852             }
853             epn.setSummaryOn(summaryOn);
854         }
855
856         epn.setToggled(isActive);
857         epn.setPhoneNumber(number);
858     }
859
860     // set the state of the UI based on CF State
861     private void syncCFUIState(int reason, CallForwardInfo info) {
862         boolean active = (info.status == 1);
863         switch (reason) {
864             case CommandsInterface.CF_REASON_UNCONDITIONAL:
865                 if (DBG) log("syncCFUIState: Setting UI state consistent with CFU.");
866                 adjustCFbuttonState(mButtonCFU, active, R.string.sum_cfu_enabled, info.number);
867                 mDialingNumCFU = info.number;
868                 break;
869             case CommandsInterface.CF_REASON_BUSY:
870                 if (DBG) log("syncCFUIState: Setting UI state consistent with CFB.");
871                 adjustCFbuttonState(mButtonCFB, active, R.string.sum_cfb_enabled, info.number);
872                 mDialingNumCFB = info.number;
873                 break;
874             case CommandsInterface.CF_REASON_NO_REPLY:
875                 if (DBG) log("syncCFUIState: Setting UI state consistent with CFNRy.");
876                 adjustCFbuttonState(mButtonCFNRy, active, R.string.sum_cfnry_enabled, info.number);
877                 mDialingNumCFNRy = info.number;
878                 break;
879             case CommandsInterface.CF_REASON_NOT_REACHABLE:
880                 if (DBG) log("syncCFUIState: Setting UI state consistent with CFNRc.");
881                 adjustCFbuttonState(mButtonCFNRc, active, R.string.sum_cfnrc_enabled, info.number);
882                 mDialingNumCFNRc = info.number;
883                 break;
884         }
885     }
886
887     // update the voicemail number from what we've recorded on the sim.
888     private void updateVoiceNumberField() {
889         if (mSubMenuVoicemailSettings == null) {
890             return;
891         }
892
893         mOldVmNumber = mPhone.getVoiceMailNumber();
894         if (mOldVmNumber == null) {
895             mOldVmNumber = "";
896         }
897         mSubMenuVoicemailSettings.setPhoneNumber(mOldVmNumber);
898     }
899
900
901     /*
902      * Helper Methods for Activity class.
903      * The inital query commands are split into two pieces now
904      * for individual expansion.  This combined with the ability
905      * to cancel queries allows for a much better user experience,
906      * and also ensures that the user only waits to update the
907      * data that is relevant.
908      */
909
910     // Handler to track service availability.
911     private Handler mNetworkServiceHandler = new Handler() {
912         @Override
913         public void handleMessage(Message msg) {
914             switch (msg.what) {
915                 case EVENT_SERVICE_STATE_CHANGED: {
916                         ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
917                         if (state.getState() == ServiceState.STATE_IN_SERVICE) {
918                             if (DBG) {
919                                 log("mNetworkServiceHandler: network available for queries.");
920                             }
921                             // Query ONLY what we are interested in now.
922                             switch (mDisplayMode) {
923                                 case DISP_MODE_CF:
924                                     queryAllCFOptions();
925                                     break;
926                                 case DISP_MODE_MORE:
927                                     queryMoreOptions();
928                                     break;
929                             }
930
931                             mPhone.unregisterForServiceStateChanged(mNetworkServiceHandler);
932                         }
933                     }
934                     break;
935                 case EVENT_INITAL_QUERY_CANCELED:
936                     if (DBG) log("mNetworkServiceHandler: cancel query requested.");
937                     dismissExpandedDialog();
938                     break;
939             }
940         }
941     };
942
943     // Request to begin querying for all options.
944     private void queryAllCFOptions() {
945         if (DBG) log("queryAllCFOptions: begin querying call features.");
946         mPhone.getCallForwardingOption(CommandsInterface.CF_REASON_UNCONDITIONAL,
947                 Message.obtain(mGetAllCFOptionsComplete, EVENT_CF_EXECUTED,
948                         CommandsInterface.CF_REASON_UNCONDITIONAL, 0));
949     }
950
951     // callback after each step of querying for all options.
952     private Handler mGetAllCFOptionsComplete = new Handler() {
953         @Override
954         public void handleMessage(Message msg) {
955
956             AsyncResult ar = (AsyncResult) msg.obj;
957             int status = MSG_OK;
958
959             switch (msg.what) {
960                 case EVENT_CF_EXECUTED:
961                     status = handleGetCFMessage(ar, msg.arg1);
962                     int nextReason = -1;
963                     switch (msg.arg1) {
964                         case CommandsInterface.CF_REASON_UNCONDITIONAL:
965                             if (DBG) log("mGetAllOptionsComplete: CFU query done, querying CFB.");
966                             nextReason = CommandsInterface.CF_REASON_BUSY;
967                             break;
968                         case CommandsInterface.CF_REASON_BUSY:
969                             if (DBG) {
970                                 log("mGetAllOptionsComplete: CFB query done, querying CFNRy.");
971                             }
972                             nextReason = CommandsInterface.CF_REASON_NO_REPLY;
973                             break;
974                         case CommandsInterface.CF_REASON_NO_REPLY:
975                             if (DBG) {
976                                 log("mGetAllOptionsComplete: CFNRy query done, querying CFNRc.");
977                             }
978                             nextReason = CommandsInterface.CF_REASON_NOT_REACHABLE;
979                             break;
980                         case CommandsInterface.CF_REASON_NOT_REACHABLE:
981                             if (DBG) {
982                                 log("mGetAllOptionsComplete: CFNRc query done, querying CLIR.");
983                             }
984                             break;
985                         default:
986                             // TODO: should never reach this, may want to throw exception
987                     }
988                     if (status != MSG_OK) {
989                         setAppState(AppState.NETWORK_ERROR, status);
990                     } else {
991                         if (nextReason != -1) {
992                             mPhone.getCallForwardingOption(nextReason,
993                                     Message.obtain(mGetAllCFOptionsComplete, EVENT_CF_EXECUTED,
994                                             nextReason, 0));
995                         } else {
996                             mCFDataStale = false;
997                             setAppState(AppState.INPUT_READY);
998                         }
999                     }
1000                     break;
1001
1002                 default:
1003                     // TODO: should never reach this, may want to throw exception
1004                     break;
1005             }
1006         }
1007     };
1008
1009     // Request to begin querying for all options.
1010     private void queryMoreOptions() {
1011         if (DBG) log("queryMoreOptions: begin querying call features.");
1012         mPhone.getOutgoingCallerIdDisplay(
1013                 Message.obtain(mGetMoreOptionsComplete, EVENT_CLIR_EXECUTED));
1014     }
1015
1016     // callback after each step of querying for all options.
1017     private Handler mGetMoreOptionsComplete = new Handler() {
1018         @Override
1019         public void handleMessage(Message msg) {
1020
1021             AsyncResult ar = (AsyncResult) msg.obj;
1022             int status = MSG_OK;
1023
1024             switch (msg.what) {
1025                 case EVENT_CLIR_EXECUTED:
1026                     status = handleGetCLIRMessage(ar);
1027                     if (DBG) log("mGetAllOptionsComplete: CLIR query done, querying CW.");
1028                     if (status != MSG_OK) {
1029                         setAppState(AppState.NETWORK_ERROR, status);
1030                     } else {
1031                         mPhone.getCallWaiting(Message.obtain(mGetMoreOptionsComplete,
1032                                 EVENT_CW_EXECUTED));
1033                     }
1034                     break;
1035
1036                 case EVENT_CW_EXECUTED:
1037                     status = handleGetCWMessage(ar);
1038                     if (DBG) {
1039                         log("mGetAllOptionsComplete: CW query done, querying VP.");
1040                     }
1041                     if (status != MSG_OK) {
1042                         setAppState(AppState.NETWORK_ERROR, status);
1043                     } else {
1044                         if (mPhone.getPhoneName().equals("GSM")) {
1045                             mMoreDataStale = false;
1046                             setAppState(AppState.INPUT_READY);
1047                         } else {
1048                             mPhone.getEnhancedVoicePrivacy(Message.obtain(mGetMoreOptionsComplete,
1049                                 EVENT_ENHANCED_VP_EXECUTED));
1050                         }
1051                     }
1052                     break;
1053
1054                 case EVENT_ENHANCED_VP_EXECUTED:
1055                     status = handleGetVPMessage(ar, msg.arg1);
1056                     if (DBG) {
1057                         log("mGetAllOptionsComplete: VP query done, all call features queried.");
1058                     }
1059                     if (status != MSG_OK) {
1060                         setAppState(AppState.NETWORK_ERROR, status);
1061                     } else {
1062                         mMoreDataStale = false;
1063                         setAppState(AppState.INPUT_READY);
1064                     }
1065                     break;
1066
1067                 default:
1068                     // TODO: should never reach this, may want to throw exception
1069                     break;
1070             }
1071         }
1072     };
1073
1074     // dialog creation method, called by showDialog()
1075     @Override
1076     protected Dialog onCreateDialog(int id) {
1077
1078         if ((id == BUSY_DIALOG) || (id == VOICEMAIL_DIALOG_PROGRESS) ||
1079                 (id == INITIAL_BUSY_DIALOG)) {
1080             ProgressDialog dialog = new ProgressDialog(this);
1081             dialog.setTitle(getText(R.string.updating_title));
1082             dialog.setIndeterminate(true);
1083
1084             switch (id) {
1085                 case BUSY_DIALOG:
1086                     mIsBusyDialogAvailable = true;
1087                     dialog.setCancelable(false);
1088                     dialog.setMessage(getText(R.string.updating_settings));
1089                     break;
1090                 case VOICEMAIL_DIALOG_PROGRESS:
1091                     dialog.setCancelable(false);
1092                     dialog.setMessage(getText(R.string.vm_save_number));
1093                     break;
1094                 case INITIAL_BUSY_DIALOG:
1095                     // Allowing the user to cancel on the initial query.
1096                     dialog.setCancelable(true);
1097                     dialog.setCancelMessage(
1098                             mNetworkServiceHandler.obtainMessage(EVENT_INITAL_QUERY_CANCELED));
1099                     dialog.setMessage(getText(R.string.reading_settings));
1100                     break;
1101             }
1102             // make the dialog more obvious by bluring the background.
1103             dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1104
1105             return dialog;
1106
1107         // Handle error dialog codes
1108         } else if ((id == RESPONSE_ERROR) || (id == EXCEPTION_ERROR) ||
1109                 (id == VM_RESPONSE_ERROR) || (id == VM_NOCHANGE_ERROR) ||
1110                 (id == VOICEMAIL_DIALOG_CONFIRM) || (id == RADIO_OFF_ERROR)){
1111
1112             AlertDialog.Builder b = new AlertDialog.Builder(this);
1113
1114             int msgId;
1115             int titleId = R.string.error_updating_title;
1116             switch (id) {
1117                 case VOICEMAIL_DIALOG_CONFIRM:
1118                     msgId = R.string.vm_changed;
1119                     titleId = R.string.voicemail;
1120                     // Set Button 2
1121                     b.setNegativeButton(R.string.close_dialog, this);
1122                     break;
1123                 case VM_NOCHANGE_ERROR:
1124                     // even though this is technically an error,
1125                     // keep the title friendly.
1126                     msgId = R.string.no_change;
1127                     titleId = R.string.voicemail;
1128                     // Set Button 2
1129                     b.setNegativeButton(R.string.close_dialog, this);
1130                     break;
1131                 case VM_RESPONSE_ERROR:
1132                     msgId = R.string.vm_change_failed;
1133                     // Set Button 1
1134                     b.setPositiveButton(R.string.close_dialog, this);
1135                     break;
1136                 case RESPONSE_ERROR:
1137                     msgId = R.string.response_error;
1138                     // Set Button 2, tells the activity that the error is
1139                     // recoverable on dialog exit.
1140                     b.setNegativeButton(R.string.close_dialog, this);
1141                     break;
1142                 case RADIO_OFF_ERROR:
1143                     msgId = R.string.radio_off_error;
1144                     // Set Button 3
1145                     b.setNeutralButton(R.string.close_dialog, this);
1146                     break;
1147                 case EXCEPTION_ERROR:
1148                 default:
1149                     msgId = R.string.exception_error;
1150                     // Set Button 3, tells the activity that the error is
1151                     // not recoverable on dialog exit.
1152                     b.setNeutralButton(R.string.close_dialog, this);
1153                     break;
1154             }
1155
1156             b.setTitle(getText(titleId));
1157             b.setMessage(getText(msgId));
1158             b.setCancelable(false);
1159             AlertDialog dialog = b.create();
1160
1161             // make the dialog more obvious by bluring the background.
1162             dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1163
1164             return dialog;
1165         }
1166
1167         return null;
1168     }
1169
1170     // This is a method implemented for DialogInterface.OnClickListener.
1171     // Used with the error dialog to close the app, voicemail dialog to just dismiss.
1172     // Close button is mapped to BUTTON1 for the errors that close the activity,
1173     // while those that are mapped to 3 only move the preference focus.
1174     public void onClick(DialogInterface dialog, int which) {
1175         dialog.dismiss();
1176         switch (which){
1177             case DialogInterface.BUTTON3:
1178                 // Neutral Button, used when we want to cancel expansion.
1179                 dismissExpandedDialog();
1180                 break;
1181             case DialogInterface.BUTTON1:
1182                 // Negative Button
1183                 finish();
1184                 break;
1185             default:
1186                 // just let the dialog close and go back to the input
1187                 // ready state
1188                 setAppState (AppState.INPUT_READY);
1189                 // Positive Button
1190         }
1191     }
1192
1193     /** dismiss the expanded dialog view, going back to the main preference view */
1194     private void dismissExpandedDialog() {
1195         // The dialogs that can invoke this method (via onClick()), can ONLY
1196         // be reached when either expanded dialog (More or Call Forwarding)
1197         // is open.  However, the Monkey somehow managed to get to this code
1198         // without the expanded dialogs being available (1305094).  Adding null
1199         // pointer checks just as a good measure.  This should be fine because
1200         // if the expanded dialog is NOT shown, we want to ignore the dismiss
1201         // message and go to INPUT_READY anyway.
1202         switch (mDisplayMode) {
1203             case DISP_MODE_CF:
1204                 if (mButtonCFExpand != null && mButtonCFExpand.getDialog() != null) {
1205                     mButtonCFExpand.getDialog().dismiss();
1206                 }
1207                 break;
1208             case DISP_MODE_MORE:
1209                 if (mButtonGSMMoreExpand != null && mButtonGSMMoreExpand.getDialog() != null) {
1210                     // TODO - check for mButtonCDMAMoreExpand symmetry
1211                     mButtonGSMMoreExpand.getDialog().dismiss();
1212                 }
1213                 break;
1214         }
1215         mDisplayMode = DISP_MODE_MAIN;
1216         setAppState (AppState.INPUT_READY);
1217     }
1218
1219     // set the app state when no error message needs to be set.
1220     private void setAppState(AppState requestedState) throws IllegalStateException{
1221         if (requestedState == AppState.NETWORK_ERROR) {
1222             if (DBG) log("setAppState: illegal error state without reason.");
1223             throw new IllegalStateException ("illegal error state without reason.");
1224         }
1225         setAppState (requestedState, MSG_OK);
1226     }
1227
1228     // set the app state with optional status.
1229     private void setAppState(AppState requestedState, int msgStatus)
1230             throws IllegalStateException{
1231
1232         if (requestedState == mAppState) {
1233             if (DBG) log("setAppState: requestedState same as current state. ignoring.");
1234             return;
1235         }
1236
1237         // handle errors
1238         // make sure we dismiss the correct dialogs.
1239         if (requestedState == AppState.NETWORK_ERROR) {
1240             if (DBG) log("setAppState: " + requestedState + ": " + msgStatus);
1241             switch (msgStatus) {
1242                 case MSG_EXCEPTION:
1243                     if (mAppState == AppState.INITIAL_QUERY) {
1244                         dismissDialog(INITIAL_BUSY_DIALOG);
1245                     } else {
1246                         dismissBusyDialog();
1247                     }
1248                     showDialog (EXCEPTION_ERROR);
1249                     break;
1250                 case MSG_RADIO_OFF:
1251                     showDialog (RADIO_OFF_ERROR);
1252                     break;
1253                 case MSG_UNEXPECTED_RESPONSE:
1254                     if (mAppState == AppState.INITIAL_QUERY) {
1255                         dismissDialog(INITIAL_BUSY_DIALOG);
1256                     } else {
1257                         dismissBusyDialog();
1258                     }
1259                     showDialog (RESPONSE_ERROR);
1260                     break;
1261                 case MSG_VM_EXCEPTION:
1262                     dismissDialog(VOICEMAIL_DIALOG_PROGRESS);
1263                     showDialog (VM_RESPONSE_ERROR);
1264                     break;
1265                 case MSG_OK:
1266                 default:
1267                     // This should never happen.
1268             }
1269             mAppState = requestedState;
1270             return;
1271         }
1272
1273         switch (mAppState) {
1274             // We can now transition out of the NETWORK_ERROR state, when the
1275             // user is moving from the expanded views back to the main view.
1276             case NETWORK_ERROR:
1277                 if (requestedState != AppState.INPUT_READY) {
1278                     if (DBG) log("setAppState: illegal transition from NETWORK_ERROR");
1279                     throw new IllegalStateException
1280                             ("illegal transition from NETWORK_ERROR");
1281                 }
1282                 break;
1283             case INPUT_READY:
1284                 if (DBG) log("setAppState: displaying busy dialog, reason: " + requestedState);
1285                 if (requestedState == AppState.INITIAL_QUERY) {
1286                     showDialog(INITIAL_BUSY_DIALOG);
1287                 } else if (requestedState == AppState.BUSY_NETWORK_CONNECT) {
1288                     showDialog(BUSY_DIALOG);
1289                 } else if (requestedState == AppState.WAITING_NUMBER_SELECT) {
1290                     if (DBG) log("setAppState: illegal transition from INPUT_READY");
1291                     throw new IllegalStateException
1292                             ("illegal transition from INPUT_READY");
1293                 }
1294                 break;
1295             case DIALOG_OPEN:
1296                 if (requestedState == AppState.INPUT_READY) {
1297                     if (msgStatus == MSG_VM_NOCHANGE) {
1298                         showDialog(VM_NOCHANGE_ERROR);
1299                     }
1300                 } else {
1301                     if (msgStatus == MSG_VM_BUSY) {
1302                         showDialog(VOICEMAIL_DIALOG_PROGRESS);
1303                     } else {
1304                         showDialog(BUSY_DIALOG);
1305                     }
1306                 }
1307                 break;
1308             case INITIAL_QUERY:
1309                 // the initial query state can ONLY go to the input ready state.
1310                 if (requestedState != AppState.INPUT_READY) {
1311                     if (DBG) log("setAppState: illegal transition from INITIAL_QUERY");
1312                     throw new IllegalStateException
1313                             ("illegal transition from INITIAL_QUERY");
1314                 }
1315                 dismissDialog(INITIAL_BUSY_DIALOG);
1316                 break;
1317             case BUSY_NETWORK_CONNECT:
1318                 if (requestedState != AppState.INPUT_READY) {
1319                     if (DBG) log("setAppState: illegal transition from BUSY_NETWORK_CONNECT");
1320                     throw new IllegalStateException
1321                             ("illegal transition from BUSY_NETWORK_CONNECT");
1322                 }
1323                 if (msgStatus == MSG_VM_OK) {
1324                     dismissDialog(VOICEMAIL_DIALOG_PROGRESS);
1325                     showDialog(VOICEMAIL_DIALOG_CONFIRM);
1326                 } else {
1327                     dismissBusyDialog();
1328                 }
1329                 break;
1330             case WAITING_NUMBER_SELECT:
1331                 if (requestedState != AppState.DIALOG_OPEN) {
1332                     if (DBG) log("setAppState: illegal transition from WAITING_NUMBER_SELECT");
1333                     throw new IllegalStateException
1334                             ("illegal transition from WAITING_NUMBER_SELECT");
1335                 }
1336                 dismissBusyDialog();
1337                 break;
1338         }
1339         mAppState = requestedState;
1340     }
1341
1342     /**
1343      * Make sure that the busy dialog is available before we try to close it.
1344      * This check needs to be done because the generic busy dialog is used for
1345      * a number of cases, but we need to make sure it has been displayed before
1346      * being dismissed.
1347      */
1348     private final void dismissBusyDialog() {
1349         if (mIsBusyDialogAvailable) {
1350             dismissDialog(BUSY_DIALOG);
1351         }
1352     }
1353
1354     @Override
1355     protected void onResume() {
1356         super.onResume();
1357         mPhone = PhoneFactory.getDefaultPhone();
1358
1359         // upon resumption from the sub-activity, make sure we re-enable the
1360         // preferences.
1361         getPreferenceScreen().setEnabled(true);
1362
1363         if (mPhone.getPhoneName().equals("CDMA")) {
1364             // Set UI state in onResume because a user could go home, launch some
1365             // app to change this setting's backend, and re-launch this settings app
1366             // and the UI state would be inconsistent with actual state
1367             handleSetVPMessage();
1368             mPhone.queryTTYMode(Message.obtain(mQueryTTYComplete, EVENT_TTY_EXECUTED));
1369             // TODO(Moto): Re-launch DTMF settings if necessary onResume
1370         } else {
1371             mButtonTTY.setEnabled(false);
1372             mButtonVoicePrivacy.setChecked(false);
1373             mButtonVoicePrivacy.setEnabled(false);
1374         }
1375
1376     }
1377
1378     /*
1379      * Activity class methods
1380      */
1381
1382     @Override
1383     protected void onCreate(Bundle icicle) {
1384         super.onCreate(icicle);
1385         mPhone = PhoneFactory.getDefaultPhone();
1386
1387         // If the phone loads in CDMA mode , Call Settings XML is CDMA specific
1388         // TODO: For World Phone, that has options to switch n/w mode dynamically, this
1389         // design will not work and this piece of code may be moved to onResume()
1390         if (mPhone.getPhoneName().equals("CDMA")) {
1391             addPreferencesFromResource(R.xml.cdma_call_feature_setting);
1392         } else {
1393             addPreferencesFromResource(R.xml.call_feature_setting);
1394         }
1395         // get buttons
1396         PreferenceScreen prefSet = getPreferenceScreen();
1397         mSubMenuVoicemailSettings = (EditPhoneNumberPreference)
1398                 prefSet.findPreference(BUTTON_VOICEMAIL_KEY);
1399         mSubMenuFDNSettings = (PreferenceScreen) prefSet.findPreference(BUTTON_FDN_KEY);
1400         mButtonVoicePrivacy = (CheckBoxPreference) findPreference(BUTTON_VP_KEY);
1401
1402         mButtonTTY = (ListPreference) prefSet.findPreference(BUTTON_TTY_KEY);
1403         mButtonTTY.setOnPreferenceChangeListener(this);
1404
1405         // Get the ttyMode from Settings.System and displays it
1406         int settingsTtyMode = android.provider.Settings.Secure.getInt(
1407                 mPhone.getContext().getContentResolver(),
1408                 android.provider.Settings.Secure.PREFERRED_TTY_MODE,
1409                 preferredTtyMode);
1410         mButtonTTY.setValue(Integer.toString(settingsTtyMode));
1411         UpdatePreferredTtyModeSummary(settingsTtyMode);
1412
1413         if (mPhone.getPhoneName().equals("CDMA")) {
1414             mButtonDS = (ListPreference) findPreference(BUTTON_DS_KEY);
1415             int index = Settings.System.getInt(getContentResolver(),
1416                     Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, preferredDtmfMode);
1417             mButtonDS.setValueIndex(index);
1418             mButtonDS.setOnPreferenceChangeListener(this);
1419         }
1420         if (mPhone.getPhoneName().equals("GSM")) {
1421             mButtonCLIR  = (ListPreference) prefSet.findPreference(BUTTON_CLIR_KEY);
1422             mButtonCW    = (CheckBoxPreference) prefSet.findPreference(BUTTON_CW_KEY);
1423             mButtonCFU   = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFU_KEY);
1424             mButtonCFB   = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFB_KEY);
1425             mButtonCFNRy = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFNRY_KEY);
1426             mButtonCFNRc = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFNRC_KEY);
1427
1428             // get a reference to the Preference Screens for Call Forwarding and "More" settings.
1429             mButtonCFExpand = (PreferenceScreen) prefSet.findPreference(BUTTON_CF_EXPAND_KEY);
1430             mButtonGSMMoreExpand = (PreferenceScreen) prefSet.findPreference(
1431                     BUTTON_GSM_MORE_EXPAND_KEY);
1432             mButtonCDMAMoreExpand = (PreferenceScreen) prefSet.findPreference(
1433                     BUTTON_CDMA_MORE_EXPAND_KEY);
1434
1435             // The intent code that resided here in the past has been moved into the
1436             // more conventional location in network_setting.xml
1437
1438             mButtonVoicePrivacy.setEnabled(false);
1439
1440             // Set links to the current activity and any UI settings that
1441             // effect the dialog for each preference.  Also set the
1442             // dependencies between the child (CFB, CFNRy, CFNRc)
1443             // preferences and the CFU preference.
1444             if (mButtonCFU != null){
1445                 mButtonCFU.setParentActivity(this, CommandsInterface.CF_REASON_UNCONDITIONAL, this);
1446                 mButtonCFU.setDialogOnClosedListener(this);
1447                 mButtonCFU.setDialogTitle(R.string.labelCF);
1448                 mButtonCFU.setDialogMessage(R.string.messageCFU);
1449             }
1450
1451             if (mButtonCFB != null) {
1452                 mButtonCFB.setParentActivity(this, CommandsInterface.CF_REASON_BUSY, this);
1453                 mButtonCFB.setDialogOnClosedListener(this);
1454                 mButtonCFB.setDependency(BUTTON_CFU_KEY);
1455                 mButtonCFB.setDialogTitle(R.string.labelCF);
1456                 mButtonCFB.setDialogMessage(R.string.messageCFB);
1457             }
1458
1459             if (mButtonCFNRy != null) {
1460                 mButtonCFNRy.setParentActivity(this, CommandsInterface.CF_REASON_NO_REPLY, this);
1461                 mButtonCFNRy.setDialogOnClosedListener(this);
1462                 mButtonCFNRy.setDependency(BUTTON_CFU_KEY);
1463                 mButtonCFNRy.setDialogTitle(R.string.labelCF);
1464                 mButtonCFNRy.setDialogMessage(R.string.messageCFNRy);
1465             }
1466
1467             if (mButtonCFNRc != null) {
1468                 mButtonCFNRc.setParentActivity(this, CommandsInterface.CF_REASON_NOT_REACHABLE, this);
1469                 mButtonCFNRc.setDialogOnClosedListener(this);
1470                 mButtonCFNRc.setDependency(BUTTON_CFU_KEY);
1471                 mButtonCFNRc.setDialogTitle(R.string.labelCF);
1472                 mButtonCFNRc.setDialogMessage(R.string.messageCFNRc);
1473             }
1474
1475             // set the listener for the CLIR list preference so we can issue CLIR commands.
1476             if (mButtonCLIR != null ) {
1477                 mButtonCLIR.setOnPreferenceChangeListener(this);
1478             }
1479             mFDNSettingIntent = new Intent(Intent.ACTION_MAIN);
1480             mFDNSettingIntent.setClassName(this, FdnSetting.class.getName());
1481             mSubMenuFDNSettings.setIntent (mFDNSettingIntent);
1482         }
1483
1484         if (mSubMenuVoicemailSettings != null) {
1485             mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
1486             mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
1487             mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
1488         }
1489
1490         // create intent to bring up contact list
1491         mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT);
1492         mContactListIntent.setType(android.provider.Contacts.Phones.CONTENT_ITEM_TYPE);
1493
1494         if (mSubMenuFDNSettings != null) {
1495             mFDNSettingIntent = new Intent(Intent.ACTION_MAIN);
1496             mFDNSettingIntent.setClassName(this, FdnSetting.class.getName());
1497             mSubMenuFDNSettings.setIntent (mFDNSettingIntent);
1498         }
1499
1500         mAppState = AppState.INPUT_READY;
1501
1502         if (icicle != null) {
1503             if (mButtonVoicePrivacy != null) {
1504                 mButtonVoicePrivacy.setChecked(icicle.getBoolean(BUTTON_VP_KEY));
1505             }
1506             if (mPhone.getPhoneName().equals("GSM")) {
1507                 // retrieve number state
1508                 mDialingNumCFU = icicle.getString(SUMMARY_CFU_KEY);
1509                 mDialingNumCFB = icicle.getString(SUMMARY_CFB_KEY);
1510                 mDialingNumCFNRy = icicle.getString(SUMMARY_CFNRY_KEY);
1511                 mDialingNumCFNRc = icicle.getString(SUMMARY_CFNRC_KEY);
1512
1513                 // reset CF buttons
1514                 adjustCFbuttonState(mButtonCFU, icicle.getBoolean(BUTTON_CFU_KEY),
1515                         R.string.sum_cfu_enabled, mDialingNumCFU);
1516                 adjustCFbuttonState(mButtonCFB, icicle.getBoolean(BUTTON_CFB_KEY),
1517                         R.string.sum_cfb_enabled, mDialingNumCFB);
1518                 adjustCFbuttonState(mButtonCFNRy, icicle.getBoolean(BUTTON_CFNRY_KEY),
1519                         R.string.sum_cfnry_enabled, mDialingNumCFNRy);
1520                 adjustCFbuttonState(mButtonCFNRc, icicle.getBoolean(BUTTON_CFNRC_KEY),
1521                         R.string.sum_cfnrc_enabled, mDialingNumCFNRc);
1522
1523                 // reset other button state
1524                 setButtonCLIRValue(icicle.getInt(BUTTON_CLIR_KEY));
1525                 if (mButtonCW != null) {
1526                     mButtonCW.setChecked(icicle.getBoolean(BUTTON_CW_KEY));
1527                 }
1528                 if (mButtonVoicePrivacy != null) {
1529                     mButtonVoicePrivacy.setEnabled(false);
1530                 }
1531                 mCFDataStale = icicle.getBoolean(BUTTON_CF_EXPAND_KEY);
1532                 mMoreDataStale = icicle.getBoolean(BUTTON_GSM_MORE_EXPAND_KEY);
1533             }
1534
1535             // set app state
1536             mAppState = (AppState) icicle.getSerializable(APP_STATE_KEY);
1537             mDisplayMode = icicle.getInt(DISPLAY_MODE_KEY);
1538
1539         } else {
1540             // The queries here are now lazily done, and all data is assumed stale
1541             // when we first start the activity.
1542             mCFDataStale = true;
1543             mMoreDataStale = true;
1544
1545             // check the intent that started this activity and pop up the voicemail
1546             // dialog if we've been asked to.
1547             if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
1548                 setAppState(AppState.DIALOG_OPEN);
1549                 mSubMenuVoicemailSettings.showPhoneNumberDialog();
1550             }
1551         }
1552
1553         updateVoiceNumberField();
1554     }
1555
1556     @Override
1557     protected void onSaveInstanceState(Bundle outState) {
1558         super.onSaveInstanceState(outState);
1559
1560         if (DBG) log("onSaveInstanceState: saving relevant UI state.");
1561
1562         if (mButtonVoicePrivacy != null) {
1563             outState.putBoolean(BUTTON_VP_KEY, mButtonVoicePrivacy.isChecked());
1564         }
1565         if (mButtonTTY != null) {
1566             outState.putInt(BUTTON_TTY_KEY, mButtonTTY.findIndexOfValue(mButtonTTY.getValue()));
1567         }
1568
1569         // save button state
1570         if (mPhone.getPhoneName().equals("GSM")) {
1571             if (mButtonCLIR != null) {
1572                 outState.putInt(BUTTON_CLIR_KEY, mButtonCLIR.findIndexOfValue(mButtonCLIR.getValue()));
1573             }
1574             if (mButtonCW != null) {
1575                 outState.putBoolean(BUTTON_CW_KEY, mButtonCW.isChecked());
1576             }
1577             if (mButtonCFU != null) {
1578                 outState.putBoolean(BUTTON_CFU_KEY, mButtonCFU.isToggled());
1579            }
1580             if (mButtonCFB != null) {
1581                 outState.putBoolean(BUTTON_CFB_KEY, mButtonCFB.isToggled());
1582             }
1583             if (mButtonCFNRy != null) {
1584                 outState.putBoolean(BUTTON_CFNRY_KEY, mButtonCFNRy.isToggled());
1585             }
1586             if (mButtonCFNRc != null) {
1587                  outState.putBoolean(BUTTON_CFNRC_KEY, mButtonCFNRc.isToggled());
1588             }
1589
1590             // save number state
1591             outState.putString(SUMMARY_CFU_KEY, mDialingNumCFU);
1592             outState.putString(SUMMARY_CFB_KEY, mDialingNumCFB);
1593             outState.putString(SUMMARY_CFNRY_KEY, mDialingNumCFNRy);
1594             outState.putString(SUMMARY_CFNRC_KEY, mDialingNumCFNRc);
1595
1596             outState.putBoolean(BUTTON_CF_EXPAND_KEY, mCFDataStale);
1597             outState.putBoolean(BUTTON_GSM_MORE_EXPAND_KEY, mMoreDataStale);
1598         }
1599         // save state of the app
1600         outState.putSerializable(APP_STATE_KEY, mAppState);
1601
1602         outState.putInt(DISPLAY_MODE_KEY, mDisplayMode);
1603     }
1604
1605     // TTY object
1606     private void handleTTYClickRequest(Preference preference, Object objValue) {
1607         int buttonTtyMode;
1608         buttonTtyMode = Integer.valueOf((String) objValue).intValue();
1609         int settingsTtyMode = android.provider.Settings.Secure.getInt(
1610                 mPhone.getContext().getContentResolver(),
1611                 android.provider.Settings.Secure.PREFERRED_TTY_MODE, preferredTtyMode);
1612         if (DBG) log("handleTTYClickRequest: requesting set TTY mode enable (TTY) to" +
1613                 Integer.toString(buttonTtyMode));
1614
1615         if (buttonTtyMode != settingsTtyMode) {
1616             switch(buttonTtyMode) {
1617             case Phone.TTY_MODE_OFF:
1618                 mPhone.setTTYMode(Phone.TTY_MODE_OFF,
1619                         Message.obtain(mSetTTYComplete, EVENT_TTY_MODE_SET));
1620                 break;
1621             case Phone.TTY_MODE_FULL:
1622                 mPhone.setTTYMode(Phone.TTY_MODE_FULL,
1623                         Message.obtain(mSetTTYComplete, EVENT_TTY_MODE_SET));
1624                 break;
1625             case Phone.TTY_MODE_HCO:
1626                 mPhone.setTTYMode(Phone.TTY_MODE_HCO,
1627                         Message.obtain(mSetTTYComplete, EVENT_TTY_MODE_SET));
1628                 break;
1629             case Phone.TTY_MODE_VCO:
1630                 mPhone.setTTYMode(Phone.TTY_MODE_VCO,
1631                         Message.obtain(mSetTTYComplete, EVENT_TTY_MODE_SET));
1632                 break;
1633             default:
1634                 mPhone.setTTYMode(Phone.TTY_MODE_OFF,
1635                         Message.obtain(mSetTTYComplete, EVENT_TTY_MODE_SET));
1636             }
1637             UpdatePreferredTtyModeSummary(buttonTtyMode);
1638
1639             android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1640                     android.provider.Settings.Secure.PREFERRED_TTY_MODE,
1641                     buttonTtyMode );
1642         }
1643     }
1644
1645     /*
1646      * Callback to handle TTY mode update completions
1647      */
1648
1649     // **Callback on TTY mode when complete.
1650     private Handler mSetTTYComplete = new Handler() {
1651         @Override
1652         public void handleMessage(Message msg) {
1653             // query to make sure we're looking at the same data as that in the network.
1654             switch (msg.what) {
1655                 case EVENT_TTY_EXECUTED:
1656                     handleQueryTtyResponse(msg);
1657                     onResume();
1658                     break;
1659                 case EVENT_TTY_MODE_SET:
1660                     onResume();
1661                     break;
1662                 default:
1663                     // TODO: should never reach this, may want to throw exception
1664             }
1665         }
1666     };
1667
1668     // TTY Object
1669     private void handleSetTTYMessage() {
1670         if (DBG) {
1671             log("handleSetTTYMessage: set TTY request complete, reading value from network.");
1672         }
1673         mPhone.queryTTYMode(Message.obtain(mQueryTTYComplete, EVENT_TTY_EXECUTED));
1674         android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1675                 android.provider.Settings.Secure.TTY_MODE_ENABLED, preferredTtyMode );
1676     }
1677
1678     private void handleQueryTtyResponse(Message msg) {
1679         AsyncResult ar = (AsyncResult) msg.obj;
1680
1681         if (ar.exception == null) {
1682             int ttyMode = ((int[])ar.result)[0];
1683
1684
1685
1686             int settingsTtyMode = android.provider.Settings.Secure.getInt(
1687                     mPhone.getContext().getContentResolver(),
1688                     android.provider.Settings.Secure.PREFERRED_TTY_MODE,
1689                     preferredTtyMode);
1690
1691             //check that modemNetworkMode is from an accepted value
1692             if (ttyMode == Phone.TTY_MODE_OFF ||
1693                     ttyMode == Phone.TTY_MODE_HCO ||
1694                     ttyMode == Phone.TTY_MODE_VCO ||
1695                     ttyMode == Phone.TTY_MODE_FULL) {
1696
1697                 //check changes in modemNetworkMode and updates settingsNetworkMode
1698                 if (ttyMode != settingsTtyMode) {
1699                     if (DBG) {
1700                         log("handleGetPreferredNetworkTypeResponse: if 2: " +
1701                                 "modemNetworkMode != settingsNetworkMode");
1702                     }
1703
1704                     settingsTtyMode = ttyMode;
1705
1706                     if (DBG) { log("handleGetPreferredNetworkTypeResponse: if 2: " +
1707                             "settingsNetworkMode = " + settingsTtyMode);
1708                     }
1709
1710                     //changes the Settings.System accordingly to modemNetworkMode
1711                     android.provider.Settings.Secure.putInt(
1712                             mPhone.getContext().getContentResolver(),
1713                             android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
1714                             settingsTtyMode);
1715                 }
1716
1717                 UpdatePreferredTtyModeSummary(ttyMode);
1718                 // changes the mButtonPreferredNetworkMode accordingly to modemNetworkMode
1719                 mButtonTTY.setValue(Integer.toString(ttyMode));
1720             } else {
1721                 if (DBG) log("handleGetPreferredNetworkTypeResponse: else: reset to default");
1722                 resetTtyModeToDefault();
1723             }
1724         }
1725     }
1726
1727     private void resetTtyModeToDefault() {
1728         //set the mButtonPreferredTtyMode
1729         mButtonTTY.setValue(Integer.toString(preferredTtyMode));
1730         //set the Settings.System
1731         android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1732                     android.provider.Settings.Secure.PREFERRED_TTY_MODE,
1733                     preferredTtyMode );
1734         //Set the Modem
1735         mPhone.setTTYMode(preferredTtyMode,
1736                 Message.obtain(mSetTTYComplete, EVENT_TTY_EXECUTED));
1737     }
1738
1739     private void UpdatePreferredTtyModeSummary(int TtyMode) {
1740         switch(TtyMode) {
1741             case Phone.TTY_MODE_OFF:
1742                 mButtonTTY.setSummary("TTY Mode OFF");
1743                 break;
1744             case Phone.TTY_MODE_HCO:
1745                 mButtonTTY.setSummary("TTY Mode HCO");
1746                 break;
1747             case Phone.TTY_MODE_VCO:
1748                 mButtonTTY.setSummary("TTY Mode VCO");
1749                 break;
1750             case Phone.TTY_MODE_FULL:
1751                 mButtonTTY.setSummary("TTY Mode Full");
1752                 break;
1753             default:
1754                 mButtonTTY.setSummary("TTY Mode OFF");
1755         }
1756     }
1757
1758     /*
1759      * Callback to handle query completions
1760      */
1761
1762     // **Callback on option getting when complete.
1763     private Handler mQueryTTYComplete = new Handler() {
1764         @Override
1765         public void handleMessage(Message msg) {
1766             switch (msg.what) {
1767                 case EVENT_TTY_EXECUTED:
1768                     handleQueryTTYModeMessage((AsyncResult) msg.obj);
1769                     break;
1770                 default:
1771                     // TODO: should never reach this, may want to throw exception
1772             }
1773         }
1774     };
1775
1776     // TTY Object
1777     private int handleQueryTTYModeMessage(AsyncResult ar) {
1778         if (ar.exception != null) {
1779             if (DBG) log("handleQueryTTYModeMessage: Error getting TTY enable state.");
1780             return MSG_EXCEPTION;
1781         } else {
1782             if (DBG) log("handleQueryTTYModeMessage: TTY enable state successfully queried.");
1783             syncTTYState((int[]) ar.result);
1784             android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1785                     android.provider.Settings.Secure.TTY_MODE_ENABLED, preferredTtyMode );
1786         }
1787         return MSG_OK;
1788     }
1789     /**
1790      * Tells the StatusBar whether the TTY mode is enabled or disabled
1791      */
1792     private static void setStatusBarIcon(Context context, boolean enabled) {
1793         Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
1794         ttyModeChanged.putExtra("ttyEnabled", enabled);
1795         context.sendBroadcast(ttyModeChanged);
1796     }
1797
1798     // set the state of the UI based on TTY State
1799     private void syncTTYState(int ttyArray[]) {
1800     if (DBG) log("syncTTYState: Setting UI state consistent with TTY enable state of " +
1801            ((ttyArray[0] != 0) ? "ENABLED" : "DISABLED"));
1802
1803         Context context = this;
1804
1805         if (ttyArray[0] == 0) {
1806             // turn off TTY icon at StatusBar
1807             setStatusBarIcon(context, false);
1808         }
1809         else {
1810             //display TTY icon at StatusBar
1811             setStatusBarIcon(context, true);
1812         }
1813     }
1814
1815
1816     //VP object click
1817     private void handleVoicePrivacyClickRequest(boolean value) {
1818         mPhone.enableEnhancedVoicePrivacy(value, Message.obtain(mSetVoicePrivacyComplete,
1819                 EVENT_ENHANCED_VP_EXECUTED));
1820     }
1821
1822     // **Callback on VP mode when complete.
1823     private Handler mSetVoicePrivacyComplete = new Handler() {
1824         @Override
1825         public void handleMessage(Message msg) {
1826             // query to make sure we're looking at the same data as that in the network.
1827             switch (msg.what) {
1828                 case EVENT_ENHANCED_VP_EXECUTED:
1829                     handleSetVPMessage();
1830                     break;
1831                 default:
1832                     // TODO: should never reach this, may want to throw exception
1833             }
1834         }
1835     };
1836
1837     // VP Object Set
1838     private void handleSetVPMessage() {
1839         mPhone.getEnhancedVoicePrivacy(Message.obtain(mQueryVoicePrivacyComplete,
1840                 EVENT_ENHANCED_VP_EXECUTED));
1841         android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1842                 android.provider.Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED, preferredVPMode);
1843     }
1844
1845     /*
1846      * Callback to handle VP query completions
1847      */
1848
1849     // **Callback on option getting when complete.
1850     private Handler mQueryVoicePrivacyComplete = new Handler() {
1851         @Override
1852         public void handleMessage(Message msg) {
1853             switch (msg.what) {
1854                 case EVENT_ENHANCED_VP_EXECUTED:
1855                     handleQueryVPModeMessage((AsyncResult) msg.obj);
1856                     break;
1857                 default:
1858                     // TODO: should never reach this, may want to throw exception
1859             }
1860         }
1861     };
1862
1863     // VP Object Query
1864     private int handleQueryVPModeMessage(AsyncResult ar) {
1865         if (ar.exception != null) {
1866             if (DBG) {
1867                 log("handleQueryVPModeMessage: Error getting VoicePrivacy enable state.");
1868             }
1869             return MSG_EXCEPTION;
1870         } else {
1871             if (DBG) {
1872                 log("handleQueryVPModeMessage: VoicePrivacy enable state successfully queried.");
1873             }
1874             syncVPState((int[]) ar.result);
1875             android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1876                     android.provider.Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED,
1877                     preferredVPMode );
1878         }
1879         return MSG_OK;
1880     }
1881
1882     // set the state of the UI based on VP state
1883     private void syncVPState(int vpArray[]) {
1884         Log.d(LOG_TAG, "syncVPState: Setting UI state consistent with VP enable state of"
1885                 + ((vpArray[0] != 0) ? "ENABLED" : "DISABLED"));
1886         mButtonVoicePrivacy.setChecked(vpArray[0] != 0);
1887     }
1888
1889     private static void log(String msg) {
1890         Log.d(LOG_TAG, msg);
1891     }
1892 }