FileDocCategorySizeDatePackage
CallFeaturesSetting.javaAPI DocAndroid 1.5 API59601Wed May 06 22:42:46 BST 2009com.android.phone

CallFeaturesSetting

public class CallFeaturesSetting extends android.preference.PreferenceActivity implements EditPhoneNumberPreference.GetDefaultNumberListener, DialogInterface.OnClickListener, EditPhoneNumberPreference.OnDialogClosedListener, Preference.OnPreferenceChangeListener

Fields Summary
public static final String
ACTION_ADD_VOICEMAIL
private static final String
LOG_TAG
private static final boolean
DBG
private static final String[]
NUM_PROJECTION
private static final String[]
SRC_TAGS
private static final String
BUTTON_CLIR_KEY
private static final String
BUTTON_CW_KEY
private static final String
BUTTON_CFU_KEY
private static final String
BUTTON_CFB_KEY
private static final String
BUTTON_CFNRY_KEY
private static final String
BUTTON_CFNRC_KEY
private static final String
BUTTON_VOICEMAIL_KEY
private static final String
BUTTON_FDN_KEY
private static final String
BUTTON_CF_EXPAND_KEY
private static final String
BUTTON_MORE_EXPAND_KEY
private static final String
SUMMARY_CFU_KEY
private static final String
SUMMARY_CFB_KEY
private static final String
SUMMARY_CFNRY_KEY
private static final String
SUMMARY_CFNRC_KEY
private static final String
APP_STATE_KEY
private static final String
DISPLAY_MODE_KEY
private android.content.Intent
mContactListIntent
private android.content.Intent
mFDNSettingIntent
private static final int
EVENT_SERVICE_STATE_CHANGED
private static final int
EVENT_CLIR_EXECUTED
private static final int
EVENT_CW_EXECUTED
private static final int
EVENT_CF_EXECUTED
private static final int
EVENT_VOICEMAIL_CHANGED
Event for Async voicemail change call
private static final int
EVENT_INITAL_QUERY_CANCELED
track the query cancel event.
private static final int
VOICEMAIL_PREF_ID
Handle to voicemail pref
private com.android.internal.telephony.Phone
mPhone
private static final int
BUSY_DIALOG
private static final int
EXCEPTION_ERROR
private static final int
RESPONSE_ERROR
private static final int
VM_NOCHANGE_ERROR
private static final int
VM_RESPONSE_ERROR
private static final int
RADIO_OFF_ERROR
used to track errors with the radio off.
private static final int
INITIAL_BUSY_DIALOG
private static final int
VOICEMAIL_DIALOG_CONFIRM
private static final int
VOICEMAIL_DIALOG_PROGRESS
private static final int
MSG_OK
private static final int
MSG_EXCEPTION
private static final int
MSG_UNEXPECTED_RESPONSE
private static final int
MSG_VM_EXCEPTION
private static final int
MSG_VM_BUSY
private static final int
MSG_VM_OK
private static final int
MSG_VM_NOCHANGE
private static final int
MSG_RADIO_OFF
private AppState
mAppState
private static final int
DISP_MODE_MAIN
Additional state tracking to handle expanded views (lazy queries)
private static final int
DISP_MODE_CF
private static final int
DISP_MODE_MORE
private int
mDisplayMode
private boolean
mCFDataStale
private boolean
mMoreDataStale
private boolean
mIsBusyDialogAvailable
private android.preference.PreferenceScreen
mSubMenuFDNSettings
private android.preference.ListPreference
mButtonCLIR
private android.preference.CheckBoxPreference
mButtonCW
private EditPhoneNumberPreference
mButtonCFU
private EditPhoneNumberPreference
mButtonCFB
private EditPhoneNumberPreference
mButtonCFNRy
private EditPhoneNumberPreference
mButtonCFNRc
private EditPhoneNumberPreference
mSubMenuVoicemailSettings
private android.preference.PreferenceScreen
mButtonCFExpand
private android.preference.PreferenceScreen
mButtonMoreExpand
private String
mDialingNumCFU
private String
mDialingNumCFB
private String
mDialingNumCFNRy
private String
mDialingNumCFNRc
private String
mOldVmNumber
string to hold old voicemail number as it is being updated.
private android.os.Handler
mSetOptionComplete
private android.os.Handler
mGetOptionComplete
private android.os.Handler
mNetworkServiceHandler
private android.os.Handler
mGetAllCFOptionsComplete
private android.os.Handler
mGetMoreOptionsComplete
Constructors Summary
Methods Summary
private voidadjustCFbuttonState(EditPhoneNumberPreference epn, boolean isActive, int template, java.lang.String number)

        
        if (epn == null) {
            return;
        }
        
        CharSequence summaryOn = "";

        if (isActive) {
            if (number != null) {
                String values[] = {number};
                summaryOn = TextUtils.replace(getText(template), SRC_TAGS, values);
            }
            epn.setSummaryOn(summaryOn);
        }

        epn.setToggled(isActive);
        epn.setPhoneNumber(number);
    
private final voiddismissBusyDialog()
Make sure that the busy dialog is available before we try to close it. This check needs to be done because the generic busy dialog is used for a number of cases, but we need to make sure it has been displayed before being dismissed.

        if (mIsBusyDialogAvailable) {
            dismissDialog(BUSY_DIALOG);
        }
    
private voiddismissExpandedDialog()
dismiss the expanded dialog view, going back to the main preference view

        // The dialogs that can invoke this method (via onClick()), can ONLY
        // be reached when either expanded dialog (More or Call Forwarding)
        // is open.  However, the Monkey somehow managed to get to this code
        // without the expanded dialogs being available (1305094).  Adding null
        // pointer checks just as a good measure.  This should be fine because
        // if the expanded dialog is NOT shown, we want to ignore the dismiss
        // message and go to INPUT_READY anyway.
        switch (mDisplayMode) {
            case DISP_MODE_CF:
                if (mButtonCFExpand != null && mButtonCFExpand.getDialog() != null) {
                    mButtonCFExpand.getDialog().dismiss();
                }
                break;
            case DISP_MODE_MORE:
                if (mButtonMoreExpand != null && mButtonMoreExpand.getDialog() != null) {
                    mButtonMoreExpand.getDialog().dismiss();
                }
                break;
        }
        mDisplayMode = DISP_MODE_MAIN;
        setAppState (AppState.INPUT_READY);
    
private voidhandleCFBtnClickRequest(int action, int reason, int time, java.lang.String number)

        if (DBG) log("handleCFBtnClickRequest: requesting set call forwarding (CF) " +
                Integer.toString(reason) + " to " + Integer.toString(action) + " with number " +
                number);
        mPhone.setCallForwardingOption(action,
                reason,
                number,
                time,
                Message.obtain(mSetOptionComplete, EVENT_CF_EXECUTED, reason, 0));
    
private voidhandleCLIRClickRequest(int i)

        if (DBG) log("handleCLIRClickRequest: requesting set Call Line Id Restriction (CLIR) to " +
                (i == CommandsInterface.CLIR_INVOCATION ? "ENABLE" :
                    (i == CommandsInterface.CLIR_SUPPRESSION ? "DISABLE" : "NETWORK DEFAULT")));
        mPhone.setOutgoingCallerIdDisplay(i,
                Message.obtain(mSetOptionComplete, EVENT_CLIR_EXECUTED));
    
private voidhandleCWClickRequest(boolean b)

        if (DBG) log("handleCWClickRequest: requesting set call waiting enable (CW) to" +
                Boolean.toString(b));
        mPhone.setCallWaiting(b, Message.obtain(mSetOptionComplete, EVENT_CW_EXECUTED));
    
private inthandleGetCFMessage(android.os.AsyncResult ar, int reason)

        // done with query, display the new settings.
        if (ar.exception != null) {
            if (DBG) log("handleGetCFMessage: Error getting CF enable state.");
            return MSG_EXCEPTION;
        } else if (ar.userObj instanceof Throwable) {
            // TODO: I don't think it makes sense to throw the error up to
            // the user, but this may be reconsidered.  For now, just log
            // the specific error and throw up a generic error.
            if (DBG) log("handleGetCFMessage: Error during set call, reason: " + reason +
                    " exception: " + ((Throwable) ar.userObj).toString());
            return MSG_UNEXPECTED_RESPONSE;
        } else {
            CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
            if (cfInfoArray.length == 0) {
                if (DBG) log("handleGetCFMessage: Error getting CF state, unexpected value.");
                return MSG_UNEXPECTED_RESPONSE;
            } else {
                // TODO: look through the information for the voice data
                // in reality, we should probably take the other service
                // classes into account, but this may be more than we
                // want to expose to the user.
                for (int i = 0, length = cfInfoArray.length; i < length; i++) {
                    if ((CommandsInterface.SERVICE_CLASS_VOICE &
                            cfInfoArray[i].serviceClass) != 0) {
                        if (DBG) {
                            log("handleGetCFMessage: CF state successfully queried for reason " +
                                Integer.toBinaryString(reason));
                        }
                        syncCFUIState(reason, cfInfoArray[i]);
                        break;
                    }
                }
            }
        }
        return MSG_OK;
    
private inthandleGetCLIRMessage(android.os.AsyncResult ar)


    // CLIR Object
        
        // done with query, display the new settings.
        if (ar.exception != null) {
            if (DBG) log("handleGetCLIRMessage: Error getting CLIR enable state.");
            return MSG_EXCEPTION;
        } else {
            int clirArray[] = (int[]) ar.result;
            if (clirArray.length != 2) {
                if (DBG) log("handleGetCLIRMessage: Error getting CLIR state, unexpected value.");
                return MSG_UNEXPECTED_RESPONSE;
            } else {
                if (DBG) log("handleGetCLIRMessage: CLIR enable state successfully queried.");
                syncCLIRUIState(clirArray);
            }
        }
        return MSG_OK;
    
private inthandleGetCWMessage(android.os.AsyncResult ar)

        if (ar.exception != null) {
            if (DBG) log("handleGetCWMessage: Error getting CW enable state.");
            return MSG_EXCEPTION;
        } else {
            if (DBG) log("handleGetCWMessage: CW enable state successfully queried.");
            syncCWState((int[]) ar.result);
        }
        return MSG_OK;
    
private voidhandleSetCFMessage(int reason, android.os.AsyncResult r)

        if (DBG) {
            log("handleSetCFMessage: set CF request complete, reading value back from network.");
        }

        // handle the exception in the set function's async result by
        // propagating it to the getCallForwarding function.  This is
        // so that we can display the error AFTER the setting has gone
        // through the standard (set/get) cycle.
        mPhone.getCallForwardingOption(reason,
                Message.obtain(mGetOptionComplete, EVENT_CF_EXECUTED, reason, 0, r.exception));
    
private voidhandleSetCLIRMessage()


    // CLIR Object
       
        if (DBG) {
            log("handleSetCLIRMessage: set CLIR request complete, reading value from network.");
        }
        mPhone.getOutgoingCallerIdDisplay(Message.obtain(mGetOptionComplete, EVENT_CLIR_EXECUTED));
    
private voidhandleSetCWMessage()

        if (DBG) {
            log("handleSetCWMessage: set CW request complete, reading value back from network.");
        }
        mPhone.getCallWaiting(Message.obtain(mGetOptionComplete, EVENT_CW_EXECUTED));
    
private voidhandleSetVMMessage(android.os.AsyncResult ar)

        if (DBG) {
            log("handleSetVMMessage: set VM request complete");
        }
        if (ar.exception == null) {
            if (DBG) log("change VM success!");
            setAppState(AppState.INPUT_READY, MSG_VM_OK);
        } else {
            // TODO: may want to check the exception and branch on it.
            if (DBG) log("change VM failed!");
            setAppState(AppState.NETWORK_ERROR, MSG_VM_EXCEPTION);
        }
        updateVoiceNumberField();
    
private voidhandleVMBtnClickRequest()

        // normally called on the dialog close.

        // Since we're stripping the formatting out on the getPhoneNumber()
        // call now, we won't need to do so here anymore.
        String newVMNumber = mSubMenuVoicemailSettings.getPhoneNumber();

        // empty vm number == clearing the vm number ?
        if (newVMNumber == null) {
            newVMNumber = "";
        }

        //throw a warning if they are the same.
        if (newVMNumber.equals(mOldVmNumber)) {
            setAppState(AppState.INPUT_READY, MSG_VM_NOCHANGE);
            return;
        }

        // otherwise, set it.
        setAppState (AppState.BUSY_NETWORK_CONNECT, MSG_VM_BUSY);
        if (DBG) log("save voicemail #: " + newVMNumber);
        mPhone.setVoiceMailNumber(
                mPhone.getVoiceMailAlphaTag().toString(),
                newVMNumber,
                Message.obtain(mSetOptionComplete, EVENT_VOICEMAIL_CHANGED));
    
private static voidlog(java.lang.String msg)

        Log.d(LOG_TAG, msg);
    
protected voidonActivityResult(int requestCode, int resultCode, android.content.Intent data)

        // there are cases where the contact picker may end up sending us more than one
        // request.  We want to ignore the request if we're not in the correct state.
        if (mAppState != AppState.WAITING_NUMBER_SELECT) {
            if (DBG) log("onActivityResult: wrong state, ignoring message from contact picker.");
            return;
        } else {
            setAppState(AppState.DIALOG_OPEN);
        }

        if (resultCode != RESULT_OK) {
            if (DBG) log("onActivityResult: contact picker result not OK.");
            return;
        }

        Cursor cursor = getContentResolver().query(data.getData(),
                NUM_PROJECTION, null, null, null);
        if ((cursor == null) || (!cursor.moveToFirst())) {
            if (DBG) log("onActivityResult: bad contact data, no results found.");
            return;
        }

        switch (requestCode) {
            case CommandsInterface.CF_REASON_UNCONDITIONAL:
                mButtonCFU.onPickActivityResult(cursor.getString(0));
                break;
            case CommandsInterface.CF_REASON_BUSY:
                mButtonCFB.onPickActivityResult(cursor.getString(0));
                break;
            case CommandsInterface.CF_REASON_NO_REPLY:
                mButtonCFNRy.onPickActivityResult(cursor.getString(0));
                break;
            case CommandsInterface.CF_REASON_NOT_REACHABLE:
                mButtonCFNRc.onPickActivityResult(cursor.getString(0));
                break;
            case VOICEMAIL_PREF_ID:
                mSubMenuVoicemailSettings.onPickActivityResult(cursor.getString(0));
                break;
            default:
                // TODO: may need exception here.
        }

    
public voidonClick(android.content.DialogInterface dialog, int which)

        dialog.dismiss();
        switch (which){
            case DialogInterface.BUTTON3:
                // Neutral Button, used when we want to cancel expansion.
                dismissExpandedDialog();
                break;
            case DialogInterface.BUTTON1:
                // Negative Button
                finish();
                break;
            default:
                // just let the dialog close and go back to the input
                // ready state
                setAppState (AppState.INPUT_READY);
                // Positive Button
        }
    
protected voidonCreate(android.os.Bundle icicle)

        super.onCreate(icicle);

        addPreferencesFromResource(R.xml.call_feature_setting);

        // get buttons
        PreferenceScreen prefSet = getPreferenceScreen();
        mButtonCLIR  = (ListPreference) prefSet.findPreference(BUTTON_CLIR_KEY);
        mButtonCW    = (CheckBoxPreference) prefSet.findPreference(BUTTON_CW_KEY);
        mButtonCFU   = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFU_KEY);
        mButtonCFB   = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFB_KEY);
        mButtonCFNRy = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFNRY_KEY);
        mButtonCFNRc = (EditPhoneNumberPreference) prefSet.findPreference(BUTTON_CFNRC_KEY);
        mSubMenuVoicemailSettings = (EditPhoneNumberPreference)
                prefSet.findPreference(BUTTON_VOICEMAIL_KEY);
        mSubMenuFDNSettings = (PreferenceScreen) prefSet.findPreference(BUTTON_FDN_KEY);

        // get a reference to the Preference Screens for Call Forwarding and "More" settings.
        mButtonCFExpand = (PreferenceScreen) prefSet.findPreference(BUTTON_CF_EXPAND_KEY);
        mButtonMoreExpand = (PreferenceScreen) prefSet.findPreference(BUTTON_MORE_EXPAND_KEY);

        // Set links to the current activity and any UI settings that
        // effect the dialog for each preference.  Also set the
        // dependencies between the child (CFB, CFNRy, CFNRc)
        // preferences and the CFU preference.
        if (mButtonCFU != null){
            mButtonCFU.setParentActivity(this, CommandsInterface.CF_REASON_UNCONDITIONAL, this);
            mButtonCFU.setDialogOnClosedListener(this);
            mButtonCFU.setDialogTitle(R.string.labelCF);
            mButtonCFU.setDialogMessage(R.string.messageCFU);
        }
        
        if (mButtonCFB != null) {
            mButtonCFB.setParentActivity(this, CommandsInterface.CF_REASON_BUSY, this);
            mButtonCFB.setDialogOnClosedListener(this);
            mButtonCFB.setDependency(BUTTON_CFU_KEY);
            mButtonCFB.setDialogTitle(R.string.labelCF);
            mButtonCFB.setDialogMessage(R.string.messageCFB);
        }
        
        if (mButtonCFNRy != null) {
            mButtonCFNRy.setParentActivity(this, CommandsInterface.CF_REASON_NO_REPLY, this);
            mButtonCFNRy.setDialogOnClosedListener(this);
            mButtonCFNRy.setDependency(BUTTON_CFU_KEY);
            mButtonCFNRy.setDialogTitle(R.string.labelCF);
            mButtonCFNRy.setDialogMessage(R.string.messageCFNRy);
        }
        
        if (mButtonCFNRc != null) {
            mButtonCFNRc.setParentActivity(this, CommandsInterface.CF_REASON_NOT_REACHABLE, this);
            mButtonCFNRc.setDialogOnClosedListener(this);
            mButtonCFNRc.setDependency(BUTTON_CFU_KEY);
            mButtonCFNRc.setDialogTitle(R.string.labelCF);
            mButtonCFNRc.setDialogMessage(R.string.messageCFNRc);
        }
        
        if (mSubMenuVoicemailSettings != null) {
            mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
            mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
            mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
        }
        
        // set the listener for the CLIR list preference so we can issue CLIR commands.
        if (mButtonCLIR != null ) {
            mButtonCLIR.setOnPreferenceChangeListener(this);
        }

        // create intent to bring up contact list
        mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT);
        mContactListIntent.setType(android.provider.Contacts.Phones.CONTENT_ITEM_TYPE);

        mFDNSettingIntent = new Intent(Intent.ACTION_MAIN);
        mFDNSettingIntent.setClassName(this, FdnSetting.class.getName());
        mSubMenuFDNSettings.setIntent (mFDNSettingIntent);

        mPhone = PhoneFactory.getDefaultPhone();
        mAppState = AppState.INPUT_READY;

        if (icicle != null) {
            // retrieve number state
            mDialingNumCFU = icicle.getString(SUMMARY_CFU_KEY);
            mDialingNumCFB = icicle.getString(SUMMARY_CFB_KEY);
            mDialingNumCFNRy = icicle.getString(SUMMARY_CFNRY_KEY);
            mDialingNumCFNRc = icicle.getString(SUMMARY_CFNRC_KEY);

            // reset CF buttons
            adjustCFbuttonState(mButtonCFU, icicle.getBoolean(BUTTON_CFU_KEY),
                    R.string.sum_cfu_enabled, mDialingNumCFU);
            adjustCFbuttonState(mButtonCFB, icicle.getBoolean(BUTTON_CFB_KEY),
                    R.string.sum_cfb_enabled, mDialingNumCFB);
            adjustCFbuttonState(mButtonCFNRy, icicle.getBoolean(BUTTON_CFNRY_KEY),
                    R.string.sum_cfnry_enabled, mDialingNumCFNRy);
            adjustCFbuttonState(mButtonCFNRc, icicle.getBoolean(BUTTON_CFNRC_KEY),
                    R.string.sum_cfnrc_enabled, mDialingNumCFNRc);

            // reset other button state
            setButtonCLIRValue(icicle.getInt(BUTTON_CLIR_KEY));
            if (mButtonCW != null) {
                mButtonCW.setChecked(icicle.getBoolean(BUTTON_CW_KEY));
            }

            // set app state
            mAppState = (AppState) icicle.getSerializable(APP_STATE_KEY);
            mCFDataStale = icicle.getBoolean(BUTTON_CF_EXPAND_KEY);
            mMoreDataStale = icicle.getBoolean(BUTTON_MORE_EXPAND_KEY);
            mDisplayMode = icicle.getInt(DISPLAY_MODE_KEY);

        } else {
            // The queries here are now lazily done, and all data is assumed stale
            // when we first start the activity.
            mCFDataStale = true;
            mMoreDataStale = true;

            // check the intent that started this activity and pop up the voicemail
            // dialog if we've been asked to.
            if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
                setAppState(AppState.DIALOG_OPEN);
                mSubMenuVoicemailSettings.showPhoneNumberDialog();
            }
        }

        updateVoiceNumberField();
    
protected android.app.DialogonCreateDialog(int id)


    // dialog creation method, called by showDialog()
    
        

        if ((id == BUSY_DIALOG) || (id == VOICEMAIL_DIALOG_PROGRESS) ||
                (id == INITIAL_BUSY_DIALOG)) {
            ProgressDialog dialog = new ProgressDialog(this);
            dialog.setTitle(getText(R.string.updating_title));
            dialog.setIndeterminate(true);

            switch (id) {
                case BUSY_DIALOG:
                    mIsBusyDialogAvailable = true;
                    dialog.setCancelable(false);
                    dialog.setMessage(getText(R.string.updating_settings));
                    break;
                case VOICEMAIL_DIALOG_PROGRESS:
                    dialog.setCancelable(false);
                    dialog.setMessage(getText(R.string.vm_save_number));
                    break;
                case INITIAL_BUSY_DIALOG:
                    // Allowing the user to cancel on the initial query.
                    dialog.setCancelable(true);
                    dialog.setCancelMessage(
                            mNetworkServiceHandler.obtainMessage(EVENT_INITAL_QUERY_CANCELED));
                    dialog.setMessage(getText(R.string.reading_settings));
                    break;
            }
            // make the dialog more obvious by bluring the background.
            dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            return dialog;

        // Handle error dialog codes
        } else if ((id == RESPONSE_ERROR) || (id == EXCEPTION_ERROR) ||
                (id == VM_RESPONSE_ERROR) || (id == VM_NOCHANGE_ERROR) ||
                (id == VOICEMAIL_DIALOG_CONFIRM) || (id == RADIO_OFF_ERROR)){

            AlertDialog.Builder b = new AlertDialog.Builder(this);

            int msgId;
            int titleId = R.string.error_updating_title;
            switch (id) {
                case VOICEMAIL_DIALOG_CONFIRM:
                    msgId = R.string.vm_changed;
                    titleId = R.string.voicemail;
                    // Set Button 2
                    b.setNegativeButton(R.string.close_dialog, this);
                    break;
                case VM_NOCHANGE_ERROR:
                    // even though this is technically an error,
                    // keep the title friendly.
                    msgId = R.string.no_change;
                    titleId = R.string.voicemail;
                    // Set Button 2
                    b.setNegativeButton(R.string.close_dialog, this);
                    break;
                case VM_RESPONSE_ERROR:
                    msgId = R.string.vm_change_failed;
                    // Set Button 1
                    b.setPositiveButton(R.string.close_dialog, this);
                    break;
                case RESPONSE_ERROR:
                    msgId = R.string.response_error;
                    // Set Button 2, tells the activity that the error is
                    // recoverable on dialog exit.
                    b.setNegativeButton(R.string.close_dialog, this);
                    break;
                case RADIO_OFF_ERROR:
                    msgId = R.string.radio_off_error;
                    // Set Button 3
                    b.setNeutralButton(R.string.close_dialog, this);
                    break;
                case EXCEPTION_ERROR:
                default:
                    msgId = R.string.exception_error;
                    // Set Button 3, tells the activity that the error is
                    // not recoverable on dialog exit.
                    b.setNeutralButton(R.string.close_dialog, this);
                    break;
            }

            b.setTitle(getText(titleId));
            b.setMessage(getText(msgId));
            b.setCancelable(false);
            AlertDialog dialog = b.create();

            // make the dialog more obvious by bluring the background.
            dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            return dialog;
        }

        return null;
    
public voidonDialogClosed(EditPhoneNumberPreference preference, int buttonClicked)

        if (mAppState != AppState.DIALOG_OPEN) {
            if (DBG) {
                log("onPreferenceClick: preference request denied, currently busy.");
            }
            return;
        } else if (buttonClicked == DialogInterface.BUTTON2) {
            // Button2 is the cancel button.
            setAppState (AppState.INPUT_READY);
            return;
        }

        if (DBG) log("onPreferenceClick: request preference click on dialog close.");

        AppState nextState = AppState.INPUT_READY;

        if (preference instanceof EditPhoneNumberPreference) {
            EditPhoneNumberPreference epn = preference;

            if (epn == mSubMenuVoicemailSettings) {
                handleVMBtnClickRequest();

            } else {
                int reason = 0;
                int time = 0;
                String number = "";
                // We use CommandsInterface.CF_ACTION_REGISTRATION for both the Enable
                // and Update (Button1) functions.
                int action = (epn.isToggled() || (buttonClicked == DialogInterface.BUTTON1)) ?
                        CommandsInterface.CF_ACTION_REGISTRATION :
                        CommandsInterface.CF_ACTION_DISABLE;

                // The formatted string seems to be giving the MMI codes some problems,
                // so we strip the formatting first before sending the number.
                number = PhoneNumberUtils.stripSeparators((epn.getPhoneNumber()));
                if (epn == mButtonCFU) {
                    nextState = AppState.BUSY_NETWORK_CONNECT;
                    reason = CommandsInterface.CF_REASON_UNCONDITIONAL;
                    mDialingNumCFU = number;
                } else if (epn == mButtonCFB) {
                    nextState = AppState.BUSY_NETWORK_CONNECT;
                    reason = CommandsInterface.CF_REASON_BUSY;
                    mDialingNumCFB = number;
                } else if (epn == mButtonCFNRy) {
                    nextState = AppState.BUSY_NETWORK_CONNECT;
                    reason = CommandsInterface.CF_REASON_NO_REPLY;
                    time = 20;
                    mDialingNumCFNRy = number;
                } else if (epn == mButtonCFNRc) {
                    nextState = AppState.BUSY_NETWORK_CONNECT;
                    reason = CommandsInterface.CF_REASON_NOT_REACHABLE;
                    mDialingNumCFNRc = number;
                }

                if (nextState == AppState.BUSY_NETWORK_CONNECT) {
                    handleCFBtnClickRequest(action, reason, time, number);
                }

                if (nextState != AppState.DIALOG_OPEN) {
                    setAppState(nextState);
                }
            }
        }
    
public java.lang.StringonGetDefaultNumber(EditPhoneNumberPreference preference)
Implemented for EditPhoneNumberPreference.GetDefaultNumberListener. This method set the default values for the various EditPhoneNumberPreference dialogs.

        if (preference == mSubMenuVoicemailSettings) {
            // update the voicemail number field, which takes care of the
            // mSubMenuVoicemailSettings itself, so we should return null.
            if (DBG) log("updating default for voicemail dialog");
            updateVoiceNumberField();
            return null;
        }

        String vmDisplay = PhoneFactory.getDefaultPhone().getVoiceMailNumber();
        if (TextUtils.isEmpty(vmDisplay)) {
            // if there is no voicemail number, we just return null to
            // indicate no contribution.
            return null;
        }

        // Return the voicemail number prepended with "VM: "
        if (DBG) log("updating default for call forwarding dialogs");
        return getString(R.string.voicemail_abbreviated) + " " + vmDisplay;
    
public booleanonPreferenceChange(android.preference.Preference preference, java.lang.Object objValue)
Implemented to support onPreferenceChangeListener to look for preference changes specifically on CLIR.

param
preference is the preference to be changed, should be mButtonCLIR.
param
objValue should be the value of the selection, NOT its localized display value.

        if (preference == mButtonCLIR) {
            // send the command and update state.
            handleCLIRClickRequest(mButtonCLIR.findIndexOfValue((String) objValue));
            setAppState(AppState.BUSY_NETWORK_CONNECT);
        }

        // always let the preference setting proceed.
        return true;
    
public booleanonPreferenceTreeClick(android.preference.PreferenceScreen preferenceScreen, android.preference.Preference preference)



    /*
     * Click Listeners, handle click based on objects attached to UI.
     */

    // Click listener for all toggle events
    
          
        if (mAppState != AppState.INPUT_READY) {
            if (DBG) {
                log("onPreferencesHierarchyClick: preference request denied, currently busy.");
            }
            return false;
        }

        if (DBG) log("onPreferencesHierarchyClick: request preference click.");

        AppState nextState = AppState.INPUT_READY;

        if (preference == mButtonCW) {
            handleCWClickRequest(mButtonCW.isChecked());
            nextState = AppState.BUSY_NETWORK_CONNECT;

        } else if (preference == mButtonCLIR) {
            // let the normal listpreference UI take care of this.
            return false;

        } else if ((preference instanceof EditPhoneNumberPreference) &&
                ((preference == mButtonCFU) || (preference == mButtonCFB) ||
                (preference == mButtonCFNRy) || (preference == mButtonCFNRc) ||
                (preference == mSubMenuVoicemailSettings))) {
            nextState = AppState.DIALOG_OPEN;
        } else if (preference == mSubMenuFDNSettings) {
            // let the intent handler from the caller take care of the
            // navigation to the FDN screen.
            return false;

        /** perform the requested expansion, and query the network.*/
        } else if (preference == mButtonCFExpand){
            setDisplayMode(DISP_MODE_CF);
            return true;
        } else if (preference == mButtonMoreExpand){
            setDisplayMode(DISP_MODE_MORE);
        }

        if (nextState != AppState.INPUT_READY) {
            setAppState(nextState);
            return true;
        }

        return false;
    
protected voidonSaveInstanceState(android.os.Bundle outState)

        super.onSaveInstanceState(outState);

        if (DBG) log("onSaveInstanceState: saving relevant UI state.");

        // save button state
        if (mButtonCLIR != null) {
            outState.putInt(BUTTON_CLIR_KEY, mButtonCLIR.findIndexOfValue(mButtonCLIR.getValue()));
        }
        if (mButtonCW != null) {
            outState.putBoolean(BUTTON_CW_KEY, mButtonCW.isChecked());
        }
        if (mButtonCFU != null) {
            outState.putBoolean(BUTTON_CFU_KEY, mButtonCFU.isToggled());
        }
        if (mButtonCFB != null) {
            outState.putBoolean(BUTTON_CFB_KEY, mButtonCFB.isToggled());
        }
        if (mButtonCFNRy != null) {
            outState.putBoolean(BUTTON_CFNRY_KEY, mButtonCFNRy.isToggled());
        }
        if (mButtonCFNRc != null) {
            outState.putBoolean(BUTTON_CFNRC_KEY, mButtonCFNRc.isToggled());
        }

        // save number state
        outState.putString(SUMMARY_CFU_KEY, mDialingNumCFU);
        outState.putString(SUMMARY_CFB_KEY, mDialingNumCFB);
        outState.putString(SUMMARY_CFNRY_KEY, mDialingNumCFNRy);
        outState.putString(SUMMARY_CFNRC_KEY, mDialingNumCFNRc);

        // save state of the app
        outState.putSerializable(APP_STATE_KEY, mAppState);
        outState.putBoolean(BUTTON_CF_EXPAND_KEY, mCFDataStale);
        outState.putBoolean(BUTTON_MORE_EXPAND_KEY, mMoreDataStale);
        outState.putInt(DISPLAY_MODE_KEY, mDisplayMode);
    
private voidqueryAllCFOptions()


    // Request to begin querying for all options.
       
        if (DBG) log("queryAllCFOptions: begin querying call features.");
        mPhone.getCallForwardingOption(CommandsInterface.CF_REASON_UNCONDITIONAL,
                Message.obtain(mGetAllCFOptionsComplete, EVENT_CF_EXECUTED,
                        CommandsInterface.CF_REASON_UNCONDITIONAL, 0));
    
private voidqueryMoreOptions()


    // Request to begin querying for all options.
       
        if (DBG) log("queryMoreOptions: begin querying call features.");
        mPhone.getOutgoingCallerIdDisplay(
                Message.obtain(mGetMoreOptionsComplete, EVENT_CLIR_EXECUTED));
    
private voidsetAppState(com.android.phone.CallFeaturesSetting$AppState requestedState)

        if (requestedState == AppState.NETWORK_ERROR) {
            if (DBG) log("setAppState: illegal error state without reason.");
            throw new IllegalStateException ("illegal error state without reason.");
        }
        setAppState (requestedState, MSG_OK);
    
private voidsetAppState(com.android.phone.CallFeaturesSetting$AppState requestedState, int msgStatus)


        if (requestedState == mAppState) {
            if (DBG) log("setAppState: requestedState same as current state. ignoring.");
            return;
        }

        // handle errors
        // make sure we dismiss the correct dialogs.
        if (requestedState == AppState.NETWORK_ERROR) {
            if (DBG) log("setAppState: " + requestedState + ": " + msgStatus);
            switch (msgStatus) {
                case MSG_EXCEPTION:
                    if (mAppState == AppState.INITIAL_QUERY) {
                        dismissDialog(INITIAL_BUSY_DIALOG);
                    } else {
                        dismissBusyDialog();
                    }
                    showDialog (EXCEPTION_ERROR);
                    break;
                case MSG_RADIO_OFF:
                    showDialog (RADIO_OFF_ERROR);
                    break;
                case MSG_UNEXPECTED_RESPONSE:
                    if (mAppState == AppState.INITIAL_QUERY) {
                        dismissDialog(INITIAL_BUSY_DIALOG);
                    } else {
                        dismissBusyDialog();
                    }
                    showDialog (RESPONSE_ERROR);
                    break;
                case MSG_VM_EXCEPTION:
                    dismissDialog(VOICEMAIL_DIALOG_PROGRESS);
                    showDialog (VM_RESPONSE_ERROR);
                    break;
                case MSG_OK:
                default:
                    // This should never happen.
            }
            mAppState = requestedState;
            return;
        }

        switch (mAppState) {
            // We can now transition out of the NETWORK_ERROR state, when the
            // user is moving from the expanded views back to the main view.
            case NETWORK_ERROR:
                if (requestedState != AppState.INPUT_READY) {
                    if (DBG) log("setAppState: illegal transition from NETWORK_ERROR");
                    throw new IllegalStateException
                            ("illegal transition from NETWORK_ERROR");
                }
                break;
            case INPUT_READY:
                if (DBG) log("setAppState: displaying busy dialog, reason: " + requestedState);
                if (requestedState == AppState.INITIAL_QUERY) {
                    showDialog(INITIAL_BUSY_DIALOG);
                } else if (requestedState == AppState.BUSY_NETWORK_CONNECT) {
                    showDialog(BUSY_DIALOG);
                } else if (requestedState == AppState.WAITING_NUMBER_SELECT) {
                    if (DBG) log("setAppState: illegal transition from INPUT_READY");
                    throw new IllegalStateException
                            ("illegal transition from INPUT_READY");
                }
                break;
            case DIALOG_OPEN:
                if (requestedState == AppState.INPUT_READY) {
                    if (msgStatus == MSG_VM_NOCHANGE) {
                        showDialog(VM_NOCHANGE_ERROR);
                    }
                } else {
                    if (msgStatus == MSG_VM_BUSY) {
                        showDialog(VOICEMAIL_DIALOG_PROGRESS);
                    } else {
                        showDialog(BUSY_DIALOG);
                    }
                }
                break;
            case INITIAL_QUERY:
                // the initial query state can ONLY go to the input ready state.
                if (requestedState != AppState.INPUT_READY) {
                    if (DBG) log("setAppState: illegal transition from INITIAL_QUERY");
                    throw new IllegalStateException
                            ("illegal transition from INITIAL_QUERY");
                }
                dismissDialog(INITIAL_BUSY_DIALOG);
                break;
            case BUSY_NETWORK_CONNECT:
                if (requestedState != AppState.INPUT_READY) {
                    if (DBG) log("setAppState: illegal transition from BUSY_NETWORK_CONNECT");
                    throw new IllegalStateException
                            ("illegal transition from BUSY_NETWORK_CONNECT");
                }
                if (msgStatus == MSG_VM_OK) {
                    dismissDialog(VOICEMAIL_DIALOG_PROGRESS);
                    showDialog(VOICEMAIL_DIALOG_CONFIRM);
                } else {
                    dismissBusyDialog();
                }
                break;
            case WAITING_NUMBER_SELECT:
                if (requestedState != AppState.DIALOG_OPEN) {
                    if (DBG) log("setAppState: illegal transition from WAITING_NUMBER_SELECT");
                    throw new IllegalStateException
                            ("illegal transition from WAITING_NUMBER_SELECT");
                }
                dismissBusyDialog();
                break;
        }
        mAppState = requestedState;
    
private voidsetButtonCLIRValue(int value)
Helper function to set both the value and the summary of the CLIR preference.

        
        if (mButtonCLIR == null) {
            return;
        }
        
        // first, set the value.
        mButtonCLIR.setValueIndex(value);

        // set the string summary to reflect the value
        int summary = R.string.sum_default_caller_id;
        switch (value) {
            case CommandsInterface.CLIR_SUPPRESSION:
                summary = R.string.sum_show_caller_id;
                break;
            case CommandsInterface.CLIR_INVOCATION:
                summary = R.string.sum_hide_caller_id;
                break;
            case CommandsInterface.CLIR_DEFAULT:
                summary = R.string.sum_default_caller_id;
                break;
        }
        mButtonCLIR.setSummary(summary);
    
public voidsetDisplayMode(int displayMode)
Perform the query request for the expanded items upon user request.

        mDisplayMode = displayMode;

        // look for the data if it is considered stale.
        if ((mCFDataStale && (displayMode == DISP_MODE_CF)) ||
                (mMoreDataStale && (displayMode == DISP_MODE_MORE))){
            if (DBG) log("setDisplayMode: performing requested expansion.");

            // If airplane mode is on, do not bother querying.
            if (Settings.System.getInt(getContentResolver(),
                    Settings.System.AIRPLANE_MODE_ON, 0) <= 0) {
                // query state if radio is available
                //  if its out of service, just wait for the radio to be ready
                //  if its neither of these states, throw up an error.
                setAppState(AppState.INITIAL_QUERY);

                int radioState = mPhone.getServiceState().getState();

                if (radioState == ServiceState.STATE_IN_SERVICE) {
                    // Query ONLY what we are currently expanding.
                    if (displayMode == DISP_MODE_CF) {
                        queryAllCFOptions();
                    } else {
                        queryMoreOptions();
                    }
                } else if (radioState == ServiceState.STATE_POWER_OFF){
                    if (DBG) log("onCreate: radio not ready, waiting for signal.");
                    mPhone.registerForServiceStateChanged(mNetworkServiceHandler,
                            EVENT_SERVICE_STATE_CHANGED, null);
                } else {
                    setAppState(AppState.NETWORK_ERROR, MSG_EXCEPTION);
                }
            } else {
                if (DBG) log("setDisplayMode: radio is off!");
                setAppState(AppState.NETWORK_ERROR, MSG_RADIO_OFF);
            }
        }
    
public voidstartActivityForResult(android.content.Intent intent, int requestCode)

        if (requestCode == -1) {
            // this is an intent requested from the preference framework.
            super.startActivityForResult(intent, requestCode);
            return;
        }

        if (mAppState != AppState.DIALOG_OPEN) {
            if (DBG) {
                log("startSubActivity: dialog start activity request denied, currently busy.");
            }
            return;
        }

        if (DBG) log("startSubActivity: starting requested subactivity");

        super.startActivityForResult(intent, requestCode);

        setAppState (AppState.WAITING_NUMBER_SELECT);
    
private voidsyncCFUIState(int reason, com.android.internal.telephony.gsm.CallForwardInfo info)

        boolean active = (info.status == 1);
        switch (reason) {
            case CommandsInterface.CF_REASON_UNCONDITIONAL:
                if (DBG) log("syncCFUIState: Setting UI state consistent with CFU.");
                adjustCFbuttonState(mButtonCFU, active, R.string.sum_cfu_enabled, info.number);
                mDialingNumCFU = info.number;
                break;
            case CommandsInterface.CF_REASON_BUSY:
                if (DBG) log("syncCFUIState: Setting UI state consistent with CFB.");
                adjustCFbuttonState(mButtonCFB, active, R.string.sum_cfb_enabled, info.number);
                mDialingNumCFB = info.number;
                break;
            case CommandsInterface.CF_REASON_NO_REPLY:
                if (DBG) log("syncCFUIState: Setting UI state consistent with CFNRy.");
                adjustCFbuttonState(mButtonCFNRy, active, R.string.sum_cfnry_enabled, info.number);
                mDialingNumCFNRy = info.number;
                break;
            case CommandsInterface.CF_REASON_NOT_REACHABLE:
                if (DBG) log("syncCFUIState: Setting UI state consistent with CFNRc.");
                adjustCFbuttonState(mButtonCFNRc, active, R.string.sum_cfnrc_enabled, info.number);
                mDialingNumCFNRc = info.number;
                break;
        }
    
private voidsyncCLIRUIState(int[] clirArgs)
The logic in this method is based upon the code in {@link CommandsInterface#getCLIR()}.

param
clirArgs is the int[2] retrieved from the getCLIR response, please refer to the link above more more details.

        if (DBG) log("syncCLIRUIState: Setting UI state consistent with CLIR.");

        // enable if the setting is valid.
        final boolean enabled = clirArgs[1] == 1 || clirArgs[1] == 3 || clirArgs[1] == 4;
        mButtonCLIR.setEnabled(enabled);

        // set the value of the preference based upon the clirArgs.
        int value = CommandsInterface.CLIR_DEFAULT;
        switch (clirArgs[1]) {
            case 1: // Permanently provisioned
            case 3: // Temporary presentation disallowed
            case 4: // Temporary presentation allowed
                switch (clirArgs[0]) {
                    case 1: // CLIR invoked
                        value = CommandsInterface.CLIR_INVOCATION;
                        break;
                    case 2: // CLIR suppressed
                        value = CommandsInterface.CLIR_SUPPRESSION;
                        break;
                    case 0: // Network default
                    default:
                        value = CommandsInterface.CLIR_DEFAULT;
                        break;
                }
                break;
            case 0: // Not Provisioned
            case 2: // Unknown (network error, etc)
            default:
                value = CommandsInterface.CLIR_DEFAULT;
                break;
        }
        setButtonCLIRValue(value);
    
private voidsyncCWState(int[] cwArray)

        if (DBG) log("syncCWState: Setting UI state consistent with CW enable state of " +
                ((cwArray[0] == 1) ? "ENABLED" : "DISABLED"));
        mButtonCW.setChecked(cwArray[0] == 1);
    
private voidupdateVoiceNumberField()

        if (mSubMenuVoicemailSettings == null) {
            return;
        }
        
        mOldVmNumber = mPhone.getVoiceMailNumber();
        if (mOldVmNumber == null) {
            mOldVmNumber = "";
        }
        mSubMenuVoicemailSettings.setPhoneNumber(mOldVmNumber);