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