Projects >> packages_apps_Phone >>3897278c8d39ac3ede871e4f9f963d145f6e895d

Chunk
Conflicting content
        } else if (preference == mVoicemailProviders) {
            final String currentProviderKey = getCurrentVoicemailProviderKey();
            final String newProviderKey = (String)objValue;
<<<<<<< HEAD

            if (currentProviderKey.equals(newProviderKey)) {
                if (DBG) log("VM provider unchanged (" + newProviderKey + ")");
            } else {
                if (DBG)
                    log("VM provider changes to " + newProviderKey + " from "
                            + mPreviousVMProviderKey);
=======
            if (DBG) log("VM provider changes to " + newProviderKey + " from " +
                    mPreviousVMProviderKey);
            if (mPreviousVMProviderKey.equals(newProviderKey)) {
                if (DBG) log("No change ");
                return true;
            }
            updateVMPreferenceWidgets(newProviderKey);
>>>>>>> 187c3941923fea81a88a47da78c5dfbf6db1f666

                mPreviousVMProviderKey = currentProviderKey;
Solution content
        } else if (preference == mVoicemailProviders) {
            final String currentProviderKey = getCurrentVoicemailProviderKey();
            final String newProviderKey = (String)objValue;
            if (DBG) log("VM provider changes to " + newProviderKey + " from " +
                    mPreviousVMProviderKey);
            if (mPreviousVMProviderKey.equals(newProviderKey)) {
                if (DBG) log("No change ");
                return true;
            }
            updateVMPreferenceWidgets(newProviderKey);

            mPreviousVMProviderKey = currentProviderKey;

            updateVMPreferenceWidgets(newProviderKey);

            final VoiceMailProviderSettings newProviderSettings =
                    loadSettingsForVoiceMailProvider(newProviderKey);

            // If the user switches to a voice mail provider and we have a
            // numbers stored for it we will automatically change the
            // phone's
            // voice mail and forwarding number to the stored ones.
            // Otherwise we will bring up provider's configuration UI.

            if (newProviderSettings == null) {
                if (DBG) log("Saved preferences not found - invoking config");
                mVMProviderSettingsForced = true;
                // Force the user into a configuration of the chosen
                // provider
                simulatePreferenceClick(mVoicemailSettings);
            } else {
                if (DBG) log("Saved preferences found - switching to them");
                saveVoiceMailAndForwardingNumber(newProviderKey, newProviderSettings);
            }
        }
        // always let the preference setting proceed.
        return true;
    }

    // Preference click listener invoked on OnDialogClosed for EditPhoneNumberPreference.
    public void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked) {
        if (DBG) log("onPreferenceClick: request preference click on dialog close: " +
                buttonClicked);
        if (buttonClicked == DialogInterface.BUTTON_NEGATIVE) {
            return;
        }
        if (preference instanceof EditPhoneNumberPreference) {
            EditPhoneNumberPreference epn = preference;

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

    /**
     * Implemented for EditPhoneNumberPreference.GetDefaultNumberListener.
     * This method set the default values for the various
     * EditPhoneNumberPreference dialogs.
     */
    public String onGetDefaultNumber(EditPhoneNumberPreference preference) {
        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 = mPhone.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;
    }


    // override the startsubactivity call to make changes in state consistent.
    @Override
    public void startActivityForResult(Intent intent, int requestCode) {
        if (requestCode == -1) {
            // this is an intent requested from the preference framework.
            super.startActivityForResult(intent, requestCode);
            return;
        }

        if (DBG) log("startSubActivity: starting requested subactivity");
        super.startActivityForResult(intent, requestCode);
    }

    private void switchToPreviousVoicemailProvider() {
        if (DBG) log("switchToPreviousVoicemailProvider " + mPreviousVMProviderKey);
        if (mPreviousVMProviderKey != null) {
            if (mVMChangeCompletedSuccesfully || mFwdChangeCompletedSuccesfully) { // we have to revert with carrier
                showDialog(VOICEMAIL_REVERTING_DIALOG);
                VoiceMailProviderSettings prevSettings =
                    loadSettingsForVoiceMailProvider(mPreviousVMProviderKey);
                if (mVMChangeCompletedSuccesfully) {
                    mNewVMNumber = prevSettings.voicemailNumber;
                    if (DBG) log("have to revert VM to " + mNewVMNumber);
                    mPhone.setVoiceMailNumber(
                            mPhone.getVoiceMailAlphaTag().toString(),
                            mNewVMNumber,
                            Message.obtain(mRevertOptionComplete, EVENT_VOICEMAIL_CHANGED));
                }
                if (mFwdChangeCompletedSuccesfully) {
                    if (DBG) log("have to revert fwd");
                    final CallForwardInfo[] prevFwdSettings = prevSettings.forwardingSettings;
                    if (prevFwdSettings != null) {
                        mForwardingChangeResults = new AsyncResult[mNewFwdSettings.length];
                        for (int i = 0; i < prevFwdSettings.length; i++) {
                            CallForwardInfo fi = prevFwdSettings[i];
                            if (DBG) log("Reverting fwd #: " + i + ": " + fi.toString());
                            mPhone.setCallForwardingOption(
                                    (fi.status == 1 ?
                                            CommandsInterface.CF_ACTION_REGISTRATION :
                                            CommandsInterface.CF_ACTION_DISABLE),
                                    fi.reason,
                                    fi.number,
                                    fi.timeSeconds,
                                    mRevertOptionComplete.obtainMessage(
                                            EVENT_FORWARDING_CHANGED, i, 0));
                         }
                    }
                }
            } else {
                if (DBG) log("No need to revert");
                onRevertDone();
            }
        }
    }

    void onRevertDone() {
        if (DBG) log("Flipping provider key back to " + mPreviousVMProviderKey);
        mVoicemailProviders.setValue(mPreviousVMProviderKey);
        updateVMPreferenceWidgets(mPreviousVMProviderKey);
        updateVoiceNumberField();
        if (mVMOrFwdSetError != 0) {
            showVMDialog(mVMOrFwdSetError);
            mVMOrFwdSetError = 0;
        }
    }

    // asynchronous result call after contacts are selected or after we return from
    // a call to the VM settings provider.
    @Override
    protected void onActivityResult(int requestCode, int resultCode, 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 (requestCode ==  VOICEMAIL_PROVIDER_CFG_ID) {
            boolean failure = false;

            // No matter how the processing of result goes lets clear the flag
            if (DBG) log("mVMProviderSettingsForced: " + mVMProviderSettingsForced);
            final boolean isVMProviderSettingsForced = mVMProviderSettingsForced;
            mVMProviderSettingsForced = false;

            String vmNum = null;
            if (resultCode != RESULT_OK) {
                if (DBG) log("onActivityResult: vm provider cfg result not OK.");
                failure = true;
            } else {
                if (data == null) {
                    if (DBG) log("onActivityResult: vm provider cfg result has no data");
                    failure = true;
                } else {
                    if (data.getBooleanExtra(SIGNOUT_EXTRA, false)) {
                        if (DBG) log("Provider requested signout");
                        if (isVMProviderSettingsForced) {
                            if (DBG) log("Going back to previous provider on signout");
                            switchToPreviousVoicemailProvider();
                        } else {
                            final String victim = getCurrentVoicemailProviderKey();
                            if (DBG) log("Relaunching activity and ignoring " + victim);
                            Intent i = new Intent(ACTION_ADD_VOICEMAIL);
                            i.putExtra(IGNORE_PROVIDER_EXTRA, victim);
                            i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            this.startActivity(i);
                        }
                        return;
                    }
                    vmNum = data.getStringExtra(VM_NUMBER_EXTRA);
                    if (vmNum == null || vmNum.length() == 0) {
                        if (DBG) log("onActivityResult: vm provider cfg result has no vmnum");
                        failure = true;
                    }
                }
            }
            if (failure) {
                if (DBG) log("Failure in return from voicemail provider");
                if (isVMProviderSettingsForced) {
                    switchToPreviousVoicemailProvider();
                } else {
                    if (DBG) log("Not switching back the provider since this is not forced config");
                }
                return;
            }
            mChangingVMorFwdDueToProviderChange = isVMProviderSettingsForced;
            final String fwdNum = data.getStringExtra(FWD_NUMBER_EXTRA);

            // TODO(iliat): It would be nice to load the current network setting for this and
            // send it to the provider when it's config is invoked so it can use this as default
            final int fwdNumTime = data.getIntExtra(FWD_NUMBER_TIME_EXTRA, 20);

            if (DBG) log("onActivityResult: vm provider cfg result " +
                    (fwdNum != null ? "has" : " does not have") + " forwarding number");
            saveVoiceMailAndForwardingNumber(getCurrentVoicemailProviderKey(),
                    new VoiceMailProviderSettings(vmNum, fwdNum, fwdNumTime));
            return;
        }

        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 VOICEMAIL_PREF_ID:
                mSubMenuVoicemailSettings.onPickActivityResult(cursor.getString(0));
                break;
            default:
                // TODO: may need exception here.
        }
    }

    // Voicemail button logic
    private void handleVMBtnClickRequest() {
        // 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.

        saveVoiceMailAndForwardingNumber(
                getCurrentVoicemailProviderKey(),
                new VoiceMailProviderSettings(mSubMenuVoicemailSettings.getPhoneNumber(),
                        FWD_SETTINGS_DONT_TOUCH));
    }

    private void showDialogIfForeground(int id) {
        if (mForeground) {
            showDialog(id);
        }
    }

    private void dismissDialogSafely(int id) {
        try {
            dismissDialog(id);
        } catch (IllegalArgumentException e) {
            // This is expected in the case where we were in the background
            // at the time we would normally have shown the dialog, so we didn't
            // show it.
        }
    }

    private void saveVoiceMailAndForwardingNumber(String key,
            VoiceMailProviderSettings newSettings) {
        if (DBG) log("saveVoiceMailAndForwardingNumber: " + newSettings.toString());
        mNewVMNumber = newSettings.voicemailNumber;
        // empty vm number == clearing the vm number ?
        if (mNewVMNumber == null) {
            mNewVMNumber = "";
        }

        mNewFwdSettings = newSettings.forwardingSettings;
        if (DBG) log("newFwdNumber " +
                String.valueOf((mNewFwdSettings != null ? mNewFwdSettings.length : 0))
                + " settings");

        // No fwd settings on CDMA
        if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
            if (DBG) log("ignoring forwarding setting since this is CDMA phone");
            mNewFwdSettings = FWD_SETTINGS_DONT_TOUCH;
        }

        //throw a warning if the vm is the same and we do not touch forwarding.
        if (mNewVMNumber.equals(mOldVmNumber) && mNewFwdSettings == FWD_SETTINGS_DONT_TOUCH) {
            showVMDialog(MSG_VM_NOCHANGE);
            return;
        }

        maybeSaveSettingsForVoicemailProvider(key, newSettings);
        mVMChangeCompletedSuccesfully = false;
        mFwdChangeCompletedSuccesfully = false;
        mVMOrFwdSetError = 0;
        // If we are switching to a non default provider - save previous forwarding
        // settings
        if (!key.equals(mPreviousVMProviderKey) &&
                mPreviousVMProviderKey.equals(DEFAULT_VM_PROVIDER_KEY)) {
            if (DBG) log("Reading current forwarding settings");
            mForwardingReadResults = new CallForwardInfo[FORWARDING_SETTINGS_REASONS.length];
            for (int i = 0; i < FORWARDING_SETTINGS_REASONS.length; i++) {
                mForwardingReadResults[i] = null;
                mPhone.getCallForwardingOption(FORWARDING_SETTINGS_REASONS[i],
                        mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0));
            }
            showDialogIfForeground(VOICEMAIL_FWD_READING_DIALOG);
        } else {
            saveVoiceMailAndForwardingNumberStage2();
        }
    }

    private Handler mGetOptionComplete = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            AsyncResult result = (AsyncResult) msg.obj;
            switch (msg.what) {
                case EVENT_FORWARDING_GET_COMPLETED:
                    handleForwardingSettingsReadResult(result, msg.arg1);
                    break;
            }
        }
    };

    void handleForwardingSettingsReadResult(AsyncResult ar, int idx) {
        if (DBG) Log.d(LOG_TAG, "handleForwardingSettingsReadResult: " + idx);
        Throwable error = null;
        if (ar.exception != null) {
            if (DBG) Log.d(LOG_TAG, "FwdRead: ar.exception=" +
                    ar.exception.getMessage());
            error = ar.exception;
        }
        if (ar.userObj instanceof Throwable) {
            if (DBG) Log.d(LOG_TAG, "FwdRead: userObj=" +
                    ((Throwable)ar.userObj).getMessage());
            error = (Throwable)ar.userObj;
        }

        // We may have already gotten an error and decided to ignore the other results.
        if (mForwardingReadResults == null) {
            if (DBG) Log.d(LOG_TAG, "ignoring fwd reading result: " + idx);
            return;
        }

        // In case of error ignore other results, show an error dialog
        if (error != null) {
            if (DBG) Log.d(LOG_TAG, "Error discovered for fwd read : " + idx);
            mForwardingReadResults = null;
            dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
            showVMDialog(MSG_FW_GET_EXCEPTION);
            return;
        }

        // Get the forwarding info
        final CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
        CallForwardInfo fi = null;
        for (int i = 0 ; i < cfInfoArray.length; i++) {
            if ((cfInfoArray[i].serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) {
                fi = cfInfoArray[i];
                break;
            }
        }
        if (fi == null) {

            // In case we go nothing it means we need this reason disabled
            // so create a CallForwardInfo for capturing this
            if (DBG) Log.d(LOG_TAG, "Creating default info for " + idx);
            fi = new CallForwardInfo();
            fi.status = 0;
            fi.reason = FORWARDING_SETTINGS_REASONS[idx];
            fi.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
        } else {
            if (DBG) Log.d(LOG_TAG, "Got  " + fi.toString() + " for " + idx);
        }
        mForwardingReadResults[idx] = fi;

        // Check if we got all the results already
        boolean done = true;
        for (int i = 0; i < mForwardingReadResults.length; i++) {
            if (mForwardingReadResults[i] == null) {
                done = false;
                break;
            }
        }
        if (done) {
            if (DBG) Log.d(LOG_TAG, "Done receiving fwd info");
            dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
            maybeSaveSettingsForVoicemailProvider(DEFAULT_VM_PROVIDER_KEY,
                    new VoiceMailProviderSettings(this.mOldVmNumber, mForwardingReadResults));
            saveVoiceMailAndForwardingNumberStage2();
        } else {
            if (DBG) Log.d(LOG_TAG, "Not done receiving fwd info");
        }
    }

    // Called after we are done saving the previous forwarding settings if
    // we needed.
    private void saveVoiceMailAndForwardingNumberStage2() {
        mForwardingChangeResults = null;
        mVoicemailChangeResult = null;
        if (mNewFwdSettings != FWD_SETTINGS_DONT_TOUCH) {
            mForwardingChangeResults = new AsyncResult[mNewFwdSettings.length];
            for (int i = 0; i < mNewFwdSettings.length; i++) {
                CallForwardInfo fi = mNewFwdSettings[i];
                if (DBG) log("Setting fwd #: " + i + ": " + fi.toString());
                mPhone.setCallForwardingOption(
                        (fi.status == 1 ?
                                CommandsInterface.CF_ACTION_REGISTRATION :
                                CommandsInterface.CF_ACTION_DISABLE),
                        fi.reason,
                        fi.number,
                        fi.timeSeconds,
                        mSetOptionComplete.obtainMessage(EVENT_FORWARDING_CHANGED, i, 0));

             }
             showDialogIfForeground(VOICEMAIL_FWD_SAVING_DIALOG);
        } else {
            if (DBG) log("Not touching fwd #");
            setVMNumberWithCarrier();
        }
    }

    void setVMNumberWithCarrier() {
        if (DBG) log("save voicemail #: " + mNewVMNumber);
        mPhone.setVoiceMailNumber(
                mPhone.getVoiceMailAlphaTag().toString(),
                mNewVMNumber,
                Message.obtain(mSetOptionComplete, EVENT_VOICEMAIL_CHANGED));
    }

    /**
     * Callback to handle option update completions
     */
    private Handler mSetOptionComplete = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            AsyncResult result = (AsyncResult) msg.obj;
            switch (msg.what) {
                case EVENT_VOICEMAIL_CHANGED:
                    mVoicemailChangeResult = result;
                    mVMChangeCompletedSuccesfully = checkVMChangeSuccess() == null;
                    if (DBG) log("VM change complete msg, VM change done = " +
                            String.valueOf(mVMChangeCompletedSuccesfully));
                    break;
                case EVENT_FORWARDING_CHANGED:
                    mForwardingChangeResults[msg.arg1] = result;
                    final boolean completed = checkForwardingCompleted();
                    if (completed) {
                        mFwdChangeCompletedSuccesfully = checkFwdChangeSuccess() == null;
                    }
                    if (DBG) log("FWD change complete msg " + msg.arg1 + ", completed=" +
                            String.valueOf(completed) + ", succesfully=" +
                            String.valueOf(mFwdChangeCompletedSuccesfully));
                    if (mFwdChangeCompletedSuccesfully) {
                        setVMNumberWithCarrier();
                    }
                    break;
                default:
                    // TODO: should never reach this, may want to throw exception
            }
            // Check if we are done - either we are only setting vm and that is done
            // or we are setting both vm and fwd and both are done.
            final boolean vmCompleted = mVoicemailChangeResult != null;

            boolean done = false;
            if (mForwardingChangeResults != null) {
                if (checkForwardingCompleted()) {
                    if (!mFwdChangeCompletedSuccesfully) {
                        done = true;
                    } else {
                        done = vmCompleted;
                    }
                }
            } else {
                done = vmCompleted;
            }
            if (done) {
                if (DBG) log("All VM related changes done");
                if (mForwardingChangeResults != null) {
                    dismissDialogSafely(VOICEMAIL_FWD_SAVING_DIALOG);
                }
                handleSetVMOrFwdMessage();
            }
        }
    };

    /**
     * Callback to handle option revert completions
     */
    private Handler mRevertOptionComplete = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            AsyncResult result = (AsyncResult) msg.obj;
            switch (msg.what) {
                case EVENT_VOICEMAIL_CHANGED:
                    mVoicemailChangeResult = result;
                    if (DBG) log("VM revert complete msg");
                    break;
                case EVENT_FORWARDING_CHANGED:
                    mForwardingChangeResults[msg.arg1] = result;
                    if (DBG) log("FWD revert complete msg ");
                    break;
                default:
                    // TODO: should never reach this, may want to throw exception
            }
            final boolean done =
                (!mVMChangeCompletedSuccesfully || mVoicemailChangeResult != null) &&
                (!mFwdChangeCompletedSuccesfully || checkForwardingCompleted());
            if (done) {
                if (DBG) log("All VM reverts done");
                dismissDialog(VOICEMAIL_REVERTING_DIALOG);
                onRevertDone();
            }
        }
    };

    /**
     * @return true if forwarding change has completed
     */
    private boolean checkForwardingCompleted() {
        if (mForwardingChangeResults == null) {
            return true;
        }
        for (int i = 0; i < mForwardingChangeResults.length; i++) {
            if (mForwardingChangeResults[i] == null) {
                return false;
            }
        }
        return true;
    }
    /**
     * @return error string or null if successful
     */
    private String checkFwdChangeSuccess() {
        for (int i = 0; i < mForwardingChangeResults.length; i++) {
            if (mForwardingChangeResults[i].exception != null) {
                final String msg = mForwardingChangeResults[i].exception.getMessage();
                if (msg == null) {
                    return "";
                }
                return msg;
            }
        }
        return null;
    }

    /**
     * @return error string or null if succesfull
     */
    private String checkVMChangeSuccess() {
        if (mVoicemailChangeResult.exception != null) {
            final String msg = mVoicemailChangeResult.exception.getMessage();
            if (msg == null) {
                return "";
            }
            return msg;
        }
        return null;
    }

    private void handleSetVMOrFwdMessage() {
        if (DBG) {
            log("handleSetVMMessage: set VM request complete");
        }
        boolean success = true;
        boolean fwdFailure = false;
        String exceptionMessage = "";
        if (mForwardingChangeResults != null) {
            exceptionMessage = checkFwdChangeSuccess();
            if (exceptionMessage != null) {
                success = false;
                fwdFailure = true;
            }
        }
        if (success) {
            exceptionMessage = checkVMChangeSuccess();
            if (exceptionMessage != null) {
                success = false;
            }
        }
        if (success) {
            if (DBG) log("change VM success!");
            handleVMAndFwdSetSuccess(MSG_VM_OK);
            updateVoiceNumberField();
        } else {
            if (fwdFailure) {
                log("change FW failed: " + exceptionMessage);
                handleVMOrFwdSetError(MSG_FW_SET_EXCEPTION);
            } else {
                log("change VM failed: " + exceptionMessage);
                handleVMOrFwdSetError(MSG_VM_EXCEPTION);
            }
        }
    }

    private void handleVMOrFwdSetError(int msgId) {
        if (mChangingVMorFwdDueToProviderChange) {
            mVMOrFwdSetError = msgId;
            mChangingVMorFwdDueToProviderChange = false;
            switchToPreviousVoicemailProvider();
            return;
        }
        mChangingVMorFwdDueToProviderChange = false;
        showVMDialog(msgId);
        updateVoiceNumberField();
    }

    private void handleVMAndFwdSetSuccess(int msgId) {
        mChangingVMorFwdDueToProviderChange = false;
        showVMDialog(msgId);
    }

    /*
     * Methods used to sync UI state with that of the network
     */
    // update the voicemail number from what we've recorded on the sim.
    private void updateVoiceNumberField() {
        if (mSubMenuVoicemailSettings == null) {
            return;
        }

        mOldVmNumber = mPhone.getVoiceMailNumber();
        if (mOldVmNumber == null) {
            mOldVmNumber = "";
        }
        mSubMenuVoicemailSettings.setPhoneNumber(mOldVmNumber);
        final String summary = (mOldVmNumber.length() > 0) ? mOldVmNumber :
            getString(R.string.voicemail_number_not_set);
        mSubMenuVoicemailSettings.setSummary(summary);
    }

    /*
     * Helper Methods for Activity class.
     * The initial query commands are split into two pieces now
     * for individual expansion.  This combined with the ability
     * to cancel queries allows for a much better user experience,
     * and also ensures that the user only waits to update the
     * data that is relevant.
     */

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        super.onPrepareDialog(id, dialog);
        mCurrentDialogId = id;
    }

    // dialog creation method, called by showDialog()
    @Override
    protected Dialog onCreateDialog(int id) {
        if ((id == VM_RESPONSE_ERROR) || (id == VM_NOCHANGE_ERROR) ||
            (id == FW_SET_RESPONSE_ERROR) || (id == FW_GET_RESPONSE_ERROR) ||
                (id == VOICEMAIL_DIALOG_CONFIRM)) {

            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 FW_SET_RESPONSE_ERROR:
                    msgId = R.string.fw_change_failed;
                    // Set Button 1
                    b.setPositiveButton(R.string.close_dialog, this);
                    break;
                case FW_GET_RESPONSE_ERROR:
                    msgId = R.string.fw_get_in_vm_failed;
                    b.setPositiveButton(R.string.alert_dialog_yes, this);
                    b.setNegativeButton(R.string.alert_dialog_no, this);
                    break;
                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));
            String message = getText(msgId).toString();
            b.setMessage(message);
            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;
        } else if (id == VOICEMAIL_FWD_SAVING_DIALOG || id == VOICEMAIL_FWD_READING_DIALOG ||
                id == VOICEMAIL_REVERTING_DIALOG) {
            ProgressDialog dialog = new ProgressDialog(this);
            dialog.setTitle(getText(R.string.updating_title));
            dialog.setIndeterminate(true);
            dialog.setCancelable(false);
            dialog.setMessage(getText(
                    id == VOICEMAIL_FWD_SAVING_DIALOG ? R.string.updating_settings :
                    (id == VOICEMAIL_REVERTING_DIALOG ? R.string.reverting_settings :
                    R.string.reading_settings)));
            return dialog;
        }


        return null;
    }

    // This is a method implemented for DialogInterface.OnClickListener.
    // Used with the error dialog to close the app, voicemail dialog to just dismiss.
    // Close button is mapped to BUTTON_POSITIVE for the errors that close the activity,
    // while those that are mapped to BUTTON_NEUTRAL only move the preference focus.
    public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();
        switch (which){
            case DialogInterface.BUTTON_NEUTRAL:
                if (DBG) log("Neutral button");
                break;
            case DialogInterface.BUTTON_NEGATIVE:
                if (DBG) log("Negative button");
                if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) {
                    // We failed to get current forwarding settings and the user
                    // does not wish to continue.
                    switchToPreviousVoicemailProvider();
                }
                break;
            case DialogInterface.BUTTON_POSITIVE:
                if (DBG) log("Positive button");
                if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) {
                    // We failed to get current forwarding settings but the user
                    // wishes to continue changing settings to the new vm provider
                    saveVoiceMailAndForwardingNumberStage2();
                } else {
                    finish();
                }
                return;
            default:
                // just let the dialog close and go back to the input
        }
        // In all dialogs, all buttons except BUTTON_POSITIVE lead to the end of user interaction
        // with settings UI. If we were called to explicitly configure voice mail then
        // we finish the settings activity here to come back to whatever the user was doing.
        if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
            finish();
        }
    }

    // set the app state with optional status.
    private void showVMDialog(int msgStatus) {
        switch (msgStatus) {
            // It's a bit worrisome to punt in the error cases here when we're
            // not in the foreground; maybe toast instead?
            case MSG_VM_EXCEPTION:
                showDialogIfForeground(VM_RESPONSE_ERROR);
                break;
            case MSG_FW_SET_EXCEPTION:
                showDialogIfForeground(FW_SET_RESPONSE_ERROR);
                break;
            case MSG_FW_GET_EXCEPTION:
                showDialogIfForeground(FW_GET_RESPONSE_ERROR);
                break;
            case MSG_VM_NOCHANGE:
                showDialogIfForeground(VM_NOCHANGE_ERROR);
                break;
            case MSG_VM_OK:
                showDialogIfForeground(VOICEMAIL_DIALOG_CONFIRM);
                break;
            case MSG_OK:
            default:
                // This should never happen.
        }
    }

    /*
     * Activity class methods
     */

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        if (DBG) log("Creating activity");
        mPhone = PhoneFactory.getDefaultPhone();

        addPreferencesFromResource(R.xml.call_feature_setting);

        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

        // get buttons
        PreferenceScreen prefSet = getPreferenceScreen();
        mSubMenuVoicemailSettings = (EditPhoneNumberPreference)findPreference(BUTTON_VOICEMAIL_KEY);
        if (mSubMenuVoicemailSettings != null) {
            mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
            mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
            mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
        }

        mButtonDTMF = (ListPreference) findPreference(BUTTON_DTMF_KEY);
        mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY);
        mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY);
        mButtonTTY = (ListPreference) findPreference(BUTTON_TTY_KEY);
        mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY);
        if (mVoicemailProviders != null) {
            mVoicemailProviders.setOnPreferenceChangeListener(this);
            mVoicemailSettings = (PreferenceScreen)findPreference(BUTTON_VOICEMAIL_SETTING_KEY);

            initVoiceMailProviders();
        }
        if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
            mButtonDTMF.setOnPreferenceChangeListener(this);
        } else {
            prefSet.removePreference(mButtonDTMF);
            mButtonDTMF = null;
        }

        if (getResources().getBoolean(R.bool.auto_retry_enabled)) {
            mButtonAutoRetry.setOnPreferenceChangeListener(this);
        } else {
            prefSet.removePreference(mButtonAutoRetry);
            mButtonAutoRetry = null;
        }

        if (getResources().getBoolean(R.bool.hac_enabled)) {
            mButtonHAC.setOnPreferenceChangeListener(this);
        } else {
            prefSet.removePreference(mButtonHAC);
            mButtonHAC = null;
        }

        if (getResources().getBoolean(R.bool.tty_enabled)) {
            mButtonTTY.setOnPreferenceChangeListener(this);
            ttyHandler = new TTYHandler();
        } else {
            prefSet.removePreference(mButtonTTY);
            mButtonTTY = null;
        }

        if (!getResources().getBoolean(R.bool.world_phone)) {
            prefSet.removePreference(prefSet.findPreference(BUTTON_CDMA_OPTIONS));
            prefSet.removePreference(prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS));

            int phoneType = mPhone.getPhoneType();
            if (phoneType == Phone.PHONE_TYPE_CDMA) {
                prefSet.removePreference(prefSet.findPreference(BUTTON_FDN_KEY));
                addPreferencesFromResource(R.xml.cdma_call_options);
            } else if (phoneType == Phone.PHONE_TYPE_GSM) {
                addPreferencesFromResource(R.xml.gsm_umts_call_options);
            } else {
                throw new IllegalStateException("Unexpected phone type: " + phoneType);
            }
        }

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

        // check the intent that started this activity and pop up the voicemail
        // dialog if we've been asked to.
        // If we have at least one non default VM provider registered then bring up
        // the selection for the VM provider, otherwise bring up a VM number dialog.
        // We only bring up the dialog the first time we are called (not after orientation change)
        if (icicle == null) {
            if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL) &&
                    mVoicemailProviders != null) {
                if (mVMProvidersData.size() > 1) {
                    simulatePreferenceClick(mVoicemailProviders);
                } else {
                    onPreferenceChange(mVoicemailProviders, DEFAULT_VM_PROVIDER_KEY);
                    mVoicemailProviders.setValue(DEFAULT_VM_PROVIDER_KEY);
                }
            }
        }
        updateVoiceNumberField();
        mVMProviderSettingsForced = false;
    }

    @Override
    protected void onResume() {
        super.onResume();
        mForeground = true;

        if (mButtonDTMF != null) {
            int dtmf = Settings.System.getInt(getContentResolver(),
                    Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_NORMAL);
            mButtonDTMF.setValueIndex(dtmf);
        }

        if (mButtonAutoRetry != null) {
            int autoretry = Settings.System.getInt(getContentResolver(),
                    Settings.System.CALL_AUTO_RETRY, 0);
            mButtonAutoRetry.setChecked(autoretry != 0);
        }

        if (mButtonHAC != null) {
            int hac = Settings.System.getInt(getContentResolver(), Settings.System.HEARING_AID, 0);
            mButtonHAC.setChecked(hac != 0);
        }

        if (mButtonTTY != null) {
            mPhone.queryTTYMode(ttyHandler.obtainMessage(TTYHandler.EVENT_TTY_MODE_GET));
        }
    }

    private void handleTTYChange(Preference preference, Object objValue) {
        int buttonTtyMode;
        buttonTtyMode = Integer.valueOf((String) objValue).intValue();
        int settingsTtyMode = android.provider.Settings.Secure.getInt(
                getContentResolver(),
                android.provider.Settings.Secure.PREFERRED_TTY_MODE, preferredTtyMode);
        if (DBG) log("handleTTYChange: requesting set TTY mode enable (TTY) to" +
                Integer.toString(buttonTtyMode));

        if (buttonTtyMode != settingsTtyMode) {
            switch(buttonTtyMode) {
            case Phone.TTY_MODE_OFF:
            case Phone.TTY_MODE_FULL:
            case Phone.TTY_MODE_HCO:
            case Phone.TTY_MODE_VCO:
                mPhone.setTTYMode(buttonTtyMode,
                        ttyHandler.obtainMessage(TTYHandler.EVENT_TTY_MODE_SET));
                break;
            default:
                mPhone.setTTYMode(Phone.TTY_MODE_OFF,
                        ttyHandler.obtainMessage(TTYHandler.EVENT_TTY_MODE_SET));
            }
        }
    }

    class TTYHandler extends Handler {
        /** Event for TTY mode change */
        private static final int EVENT_TTY_MODE_GET = 700;
        private static final int EVENT_TTY_MODE_SET = 800;

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_TTY_MODE_GET:
                    handleQueryTTYModeResponse(msg);
                    break;
                case EVENT_TTY_MODE_SET:
                    handleSetTTYModeResponse(msg);
                    break;
            }
        }

        private void updatePreferredTtyModeSummary(int TtyMode) {
            String [] txts = getResources().getStringArray(R.array.tty_mode_entries);
            switch(TtyMode) {
                case Phone.TTY_MODE_OFF:
                case Phone.TTY_MODE_HCO:
                case Phone.TTY_MODE_VCO:
                case Phone.TTY_MODE_FULL:
                    mButtonTTY.setSummary(txts[TtyMode]);
                    break;
                default:
                    mButtonTTY.setEnabled(false);
                    mButtonTTY.setSummary(txts[Phone.TTY_MODE_OFF]);
            }
        }

        private void handleQueryTTYModeResponse(Message msg) {
            AsyncResult ar = (AsyncResult) msg.obj;
            if (ar.exception != null) {
                if (DBG) log("handleQueryTTYModeResponse: Error getting TTY state.");
                mButtonTTY.setEnabled(false);
            } else {
                if (DBG) log("handleQueryTTYModeResponse: TTY enable state successfully queried.");

                int ttymode = ((int[]) ar.result)[0];
                if (DBG) log("handleQueryTTYModeResponse:ttymode=" + ttymode);

                Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
                ttyModeChanged.putExtra("ttyEnabled", ttymode != Phone.TTY_MODE_OFF);
                sendBroadcast(ttyModeChanged);
                android.provider.Settings.Secure.putInt(getContentResolver(),
                        android.provider.Settings.Secure.PREFERRED_TTY_MODE, ttymode );
                mButtonTTY.setValue(Integer.toString(ttymode));
                updatePreferredTtyModeSummary(ttymode);
            }
        }

        private void handleSetTTYModeResponse(Message msg) {
            AsyncResult ar = (AsyncResult) msg.obj;

            if (ar.exception != null) {
                if (DBG) log("handleSetTTYModeResponse: Error setting TTY mode, ar.exception"
                        + ar.exception);
            }
            mPhone.queryTTYMode(ttyHandler.obtainMessage(TTYHandler.EVENT_TTY_MODE_GET));
        }

    }

    private static void log(String msg) {
        Log.d(LOG_TAG, msg);
    }

    /**
     * Updates the look of the VM preference widgets based on current VM provider settings.
     * Note that the provider name is loaded form the found activity via loadLabel in
     * initVoiceMailProviders in order for it to be localizable.
     */
    private void updateVMPreferenceWidgets(String currentProviderSetting) {
        final String key = currentProviderSetting;
        final VoiceMailProvider provider = mVMProvidersData.get(key);

        /* This is the case when we are coming up on a freshly wiped phone and there is no
         persisted value for the list preference mVoicemailProviders.
         In this case we want to show the UI asking the user to select a voicemail provider as
         opposed to silently falling back to default one. */
        if (provider == null) {
            mVoicemailProviders.setSummary(getString(R.string.sum_voicemail_choose_provider));
            mVoicemailSettings.setSummary("");
            mVoicemailSettings.setEnabled(false);
            mVoicemailSettings.setIntent(null);
        } else {
            final String providerName = provider.name;
            mVoicemailProviders.setSummary(providerName);
            mVoicemailSettings.setSummary(getApplicationContext().getString(
                    R.string.voicemail_settings_for, providerName));
            mVoicemailSettings.setEnabled(true);
            mVoicemailSettings.setIntent(provider.intent);
        }
    }

    /**
     * Enumerates existing VM providers and puts their data into the list and populates
     * the preference list objects with their names.
     * In case we are called with ACTION_ADD_VOICEMAIL intent the intent may have
     * an extra string called IGNORE_PROVIDER_EXTRA with "package.activityName" of the provider
     * which should be hidden when we bring up the list of possible VM providers to choose.
     * This allows a provider which is being disabled (e.g. GV user logging out) to force the user
     * to pick some other provider.
     */
    private void initVoiceMailProviders() {
        mPerProviderSavedVMNumbers =
            this.getApplicationContext().getSharedPreferences(
                VM_NUMBERS_SHARED_PREFERENCES_NAME, MODE_PRIVATE);

        String providerToIgnore = null;
        if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
            if (DBG) log("ACTION_ADD_VOICEMAIL");
            if (getIntent().hasExtra(IGNORE_PROVIDER_EXTRA)) {
                providerToIgnore = getIntent().getStringExtra(IGNORE_PROVIDER_EXTRA);
            }
            if (DBG) log("providerToIgnore=" + providerToIgnore);
            if (providerToIgnore != null) {
                deleteSettingsForVoicemailProvider(providerToIgnore);
            }
        }

        mVMProvidersData.clear();

        // Stick the default element which is always there
        final String myCarrier = getString(R.string.voicemail_default);
        mVMProvidersData.put(DEFAULT_VM_PROVIDER_KEY, new VoiceMailProvider(myCarrier, null));

        // Enumerate providers
        PackageManager pm = getPackageManager();
        Intent intent = new Intent();
        intent.setAction(ACTION_CONFIGURE_VOICEMAIL);
        List resolveInfos = pm.queryIntentActivities(intent, 0);
        int len = resolveInfos.size() + 1; // +1 for the default choice we will insert.

        // Go through the list of discovered providers populating the data map
        // skip the provider we were instructed to ignore if there was one
        for (int i = 0; i < resolveInfos.size(); i++) {
            final ResolveInfo ri= resolveInfos.get(i);
            final ActivityInfo currentActivityInfo = ri.activityInfo;
            final String key = makeKeyForActivity(currentActivityInfo);
            if (DBG) log("Loading " + key);
            if (key.equals(providerToIgnore)) {
                if (DBG) log("Ignoring " + key);
                len--;
                continue;
            }
            final String nameForDisplay = ri.loadLabel(pm).toString();
            Intent providerIntent = new Intent();
            providerIntent.setAction(ACTION_CONFIGURE_VOICEMAIL);
            providerIntent.setClassName(currentActivityInfo.packageName,
                    currentActivityInfo.name);
            mVMProvidersData.put(
                    key,
                    new VoiceMailProvider(nameForDisplay, providerIntent));

        }

        // Now we know which providers to display - create entries and values array for
        // the list preference
        String [] entries = new String [len];
        String [] values = new String [len];
        entries[0] = myCarrier;
        values[0] = DEFAULT_VM_PROVIDER_KEY;
        int entryIdx = 1;
        for (int i = 0; i < resolveInfos.size(); i++) {
            final String key = makeKeyForActivity(resolveInfos.get(i).activityInfo);
            if (!mVMProvidersData.containsKey(key)) {
                continue;
            }
            entries[entryIdx] = mVMProvidersData.get(key).name;
            values[entryIdx] = key;
            entryIdx++;
        }

        mVoicemailProviders.setEntries(entries);
        mVoicemailProviders.setEntryValues(values);

        mPreviousVMProviderKey = getCurrentVoicemailProviderKey();
        updateVMPreferenceWidgets(mPreviousVMProviderKey);
    }

    private String makeKeyForActivity(ActivityInfo ai) {
        return ai.name;
    }

    /**
     * Simulates user clicking on a passed preference.
     * Usually needed when the preference is a dialog preference and we want to invoke
     * a dialog for this preference programmatically.
     * TODO(iliat): figure out if there is a cleaner way to cause preference dlg to come up
     */
    private void simulatePreferenceClick(Preference preference) {
        // Go through settings until we find our setting
        // and then simulate a click on it to bring up the dialog
        final ListAdapter adapter = getPreferenceScreen().getRootAdapter();
        for (int idx = 0; idx < adapter.getCount(); idx++) {
            if (adapter.getItem(idx) == preference) {
                getPreferenceScreen().onItemClick(this.getListView(),
                        null, idx, adapter.getItemId(idx));
                break;
            }
        }
    }

    /**
     * Saves new VM provider settings associating them with the currently selected
     * provider if settings are different than the ones already stored for this
     * provider.
     * Later on these will be used when the user switches a provider.
     */
    private void maybeSaveSettingsForVoicemailProvider(String key,
            VoiceMailProviderSettings newSettings) {
        if (mVoicemailProviders == null) {
            return;
        }
        final VoiceMailProviderSettings curSettings = loadSettingsForVoiceMailProvider(key);
        if (newSettings.equals(curSettings)) {
            if (DBG) log("Not saving setting for " + key + " since they have not changed");
            return;
        }
        if (DBG) log("Saving settings for " + key + ": " + newSettings.toString());
        Editor editor = mPerProviderSavedVMNumbers.edit();
        editor.putString(key + VM_NUMBER_TAG,newSettings.voicemailNumber);
        String fwdKey = key + FWD_SETTINGS_TAG;
        CallForwardInfo[] s = newSettings.forwardingSettings;
        if (s != FWD_SETTINGS_DONT_TOUCH) {
            editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, s.length);
            for (int i = 0; i < s.length; i++) {
                final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
                final CallForwardInfo fi = s[i];
                editor.putInt(settingKey + FWD_SETTING_STATUS, fi.status);
                editor.putInt(settingKey + FWD_SETTING_REASON, fi.reason);
                editor.putString(settingKey + FWD_SETTING_NUMBER, fi.number);
                editor.putInt(settingKey + FWD_SETTING_TIME, fi.timeSeconds);
            }
        } else {
            editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
        }
        editor.commit();
    }

    /**
     * Returns settings previously stored for the currently selected
     * voice mail provider. If none is stored returns null.
     * If the user switches to a voice mail provider and we have settings
     * stored for it we will automatically change the phone's voice mail number
     * and forwarding number to the stored one. Otherwise we will bring up provider's configuration
     * UI.
     */
    private VoiceMailProviderSettings loadSettingsForVoiceMailProvider(String key) {
        final String vmNumberSetting = mPerProviderSavedVMNumbers.getString(key + VM_NUMBER_TAG,
                null);
        if (vmNumberSetting == null) {
            if (DBG) log("Settings for " + key + " not found");
            return null;
        }

        CallForwardInfo[] cfi = FWD_SETTINGS_DONT_TOUCH;
        String fwdKey = key + FWD_SETTINGS_TAG;
        final int fwdLen = mPerProviderSavedVMNumbers.getInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
        if (fwdLen > 0) {
            cfi = new CallForwardInfo[fwdLen];
            for (int i = 0; i < cfi.length; i++) {
                final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
                cfi[i] = new CallForwardInfo();
                cfi[i].status = mPerProviderSavedVMNumbers.getInt(
                        settingKey + FWD_SETTING_STATUS, 0);
                cfi[i].reason = mPerProviderSavedVMNumbers.getInt(
                        settingKey + FWD_SETTING_REASON,
                        CommandsInterface.CF_REASON_ALL_CONDITIONAL);
                cfi[i].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
                cfi[i].toa = PhoneNumberUtils.TOA_International;
                cfi[i].number = mPerProviderSavedVMNumbers.getString(
                        settingKey + FWD_SETTING_NUMBER, "");
                cfi[i].timeSeconds = mPerProviderSavedVMNumbers.getInt(
                        settingKey + FWD_SETTING_TIME, 20);
            }
        }

        VoiceMailProviderSettings settings =  new VoiceMailProviderSettings(vmNumberSetting, cfi);
        if (DBG) log("Loaded settings for " + key + ": " + settings.toString());
        return settings;
    }

    /**
     * Deletes settings for the specified provider.
     */
    private void deleteSettingsForVoicemailProvider(String key) {
        if (DBG) log("Deleting settings for" + key);
        if (mVoicemailProviders == null) {
            return;
        }
        mPerProviderSavedVMNumbers.edit()
            .putString(key + VM_NUMBER_TAG, null)
            .putInt(key + FWD_SETTINGS_TAG + FWD_SETTINGS_LENGTH_TAG, 0)
            .commit();
    }

    private String getCurrentVoicemailProviderKey() {
        final String key = mVoicemailProviders.getValue();
        return (key != null) ? key : DEFAULT_VM_PROVIDER_KEY;
    }
}
File
CallFeaturesSetting.java
Developer's decision
Manual
Kind of conflict
If statement
Method invocation