|  | package com.android.phone; | 
|  |  | 
|  | import android.app.AlertDialog; | 
|  | import android.app.Dialog; | 
|  | import android.app.ProgressDialog; | 
|  | import android.content.DialogInterface; | 
|  | import android.preference.Preference; | 
|  | import android.preference.PreferenceActivity; | 
|  | import android.util.Log; | 
|  | import android.view.WindowManager; | 
|  |  | 
|  | import com.android.internal.telephony.CommandException; | 
|  |  | 
|  | import java.util.ArrayList; | 
|  |  | 
|  | interface  TimeConsumingPreferenceListener { | 
|  | public void onStarted(Preference preference, boolean reading); | 
|  | public void onFinished(Preference preference, boolean reading); | 
|  | public void onError(Preference preference, int error); | 
|  | public void onException(Preference preference, CommandException exception); | 
|  | } | 
|  |  | 
|  | public class TimeConsumingPreferenceActivity extends PreferenceActivity | 
|  | implements TimeConsumingPreferenceListener, | 
|  | DialogInterface.OnCancelListener { | 
|  | private static final String LOG_TAG = "TimeConsumingPrefActivity"; | 
|  | private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); | 
|  |  | 
|  | private class DismissOnClickListener implements DialogInterface.OnClickListener { | 
|  | @Override | 
|  | public void onClick(DialogInterface dialog, int which) { | 
|  | dialog.dismiss(); | 
|  | } | 
|  | } | 
|  | private class DismissAndFinishOnClickListener implements DialogInterface.OnClickListener { | 
|  | @Override | 
|  | public void onClick(DialogInterface dialog, int which) { | 
|  | dialog.dismiss(); | 
|  | finish(); | 
|  | } | 
|  | } | 
|  | private final DialogInterface.OnClickListener mDismiss = new DismissOnClickListener(); | 
|  | private final DialogInterface.OnClickListener mDismissAndFinish | 
|  | = new DismissAndFinishOnClickListener(); | 
|  |  | 
|  | private static final int BUSY_READING_DIALOG = 100; | 
|  | private static final int BUSY_SAVING_DIALOG = 200; | 
|  |  | 
|  | static final int EXCEPTION_ERROR = 300; | 
|  | static final int RESPONSE_ERROR = 400; | 
|  | static final int RADIO_OFF_ERROR = 500; | 
|  | static final int FDN_CHECK_FAILURE = 600; | 
|  | static final int STK_CC_SS_TO_DIAL_ERROR = 700; | 
|  | static final int STK_CC_SS_TO_USSD_ERROR = 800; | 
|  | static final int STK_CC_SS_TO_SS_ERROR = 900; | 
|  | static final int STK_CC_SS_TO_DIAL_VIDEO_ERROR = 1000; | 
|  |  | 
|  | private final ArrayList<String> mBusyList = new ArrayList<String>(); | 
|  |  | 
|  | protected boolean mIsForeground = false; | 
|  |  | 
|  | @Override | 
|  | protected Dialog onCreateDialog(int id) { | 
|  | if (id == BUSY_READING_DIALOG || id == BUSY_SAVING_DIALOG) { | 
|  | ProgressDialog dialog = new ProgressDialog(this); | 
|  | dialog.setTitle(getText(R.string.updating_title)); | 
|  | dialog.setIndeterminate(true); | 
|  |  | 
|  | switch(id) { | 
|  | case BUSY_READING_DIALOG: | 
|  | dialog.setCancelable(true); | 
|  | dialog.setOnCancelListener(this); | 
|  | dialog.setMessage(getText(R.string.reading_settings)); | 
|  | return dialog; | 
|  | case BUSY_SAVING_DIALOG: | 
|  | dialog.setCancelable(false); | 
|  | dialog.setMessage(getText(R.string.updating_settings)); | 
|  | return dialog; | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | if (id == RESPONSE_ERROR || id == RADIO_OFF_ERROR || id == EXCEPTION_ERROR | 
|  | || id == FDN_CHECK_FAILURE || id == STK_CC_SS_TO_DIAL_ERROR | 
|  | || id == STK_CC_SS_TO_USSD_ERROR || id == STK_CC_SS_TO_SS_ERROR | 
|  | || id == STK_CC_SS_TO_DIAL_VIDEO_ERROR) { | 
|  | AlertDialog.Builder builder = new AlertDialog.Builder(this); | 
|  |  | 
|  | int msgId; | 
|  | int titleId = R.string.error_updating_title; | 
|  |  | 
|  | switch (id) { | 
|  | case RESPONSE_ERROR: | 
|  | msgId = R.string.response_error; | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | case RADIO_OFF_ERROR: | 
|  | msgId = R.string.radio_off_error; | 
|  | // The error is not recoverable on dialog exit. | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismissAndFinish); | 
|  | break; | 
|  | case FDN_CHECK_FAILURE: | 
|  | msgId = R.string.fdn_check_failure; | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | case STK_CC_SS_TO_DIAL_ERROR: | 
|  | msgId = R.string.stk_cc_ss_to_dial_error; | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | case STK_CC_SS_TO_USSD_ERROR: | 
|  | msgId = R.string.stk_cc_ss_to_ussd_error; | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | case STK_CC_SS_TO_SS_ERROR: | 
|  | msgId = R.string.stk_cc_ss_to_ss_error; | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | case STK_CC_SS_TO_DIAL_VIDEO_ERROR: | 
|  | msgId = R.string.stk_cc_ss_to_dial_video_error; | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | case EXCEPTION_ERROR: | 
|  | default: | 
|  | msgId = R.string.exception_error; | 
|  | // The error is not recoverable on dialog exit. | 
|  | builder.setPositiveButton(R.string.close_dialog, mDismiss); | 
|  | break; | 
|  | } | 
|  |  | 
|  | builder.setTitle(getText(titleId)); | 
|  | builder.setMessage(getText(msgId)); | 
|  | builder.setCancelable(false); | 
|  | AlertDialog dialog = builder.create(); | 
|  |  | 
|  | // make the dialog more obvious by blurring the background. | 
|  | dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); | 
|  |  | 
|  | return dialog; | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onResume() { | 
|  | super.onResume(); | 
|  | mIsForeground = true; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onPause() { | 
|  | super.onPause(); | 
|  | mIsForeground = false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onStarted(Preference preference, boolean reading) { | 
|  | if (DBG) dumpState(); | 
|  | Log.i(LOG_TAG, "onStarted, preference=" + preference.getKey() + ", reading=" + reading); | 
|  | mBusyList.add(preference.getKey()); | 
|  |  | 
|  | if (mIsForeground) { | 
|  | if (reading) { | 
|  | showDialog(BUSY_READING_DIALOG); | 
|  | } else { | 
|  | showDialog(BUSY_SAVING_DIALOG); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onFinished(Preference preference, boolean reading) { | 
|  | if (DBG) dumpState(); | 
|  | Log.i(LOG_TAG, "onFinished, preference=" + preference.getKey() + ", reading=" + reading); | 
|  | mBusyList.remove(preference.getKey()); | 
|  |  | 
|  | if (mBusyList.isEmpty()) { | 
|  | if (reading) { | 
|  | dismissDialogSafely(BUSY_READING_DIALOG); | 
|  | } else { | 
|  | dismissDialogSafely(BUSY_SAVING_DIALOG); | 
|  | } | 
|  | } | 
|  | preference.setEnabled(true); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onError(Preference preference, int error) { | 
|  | if (DBG) dumpState(); | 
|  | Log.i(LOG_TAG, "onError, preference=" + preference.getKey() + ", error=" + error); | 
|  |  | 
|  | if (mIsForeground) { | 
|  | showDialog(error); | 
|  | } | 
|  | preference.setEnabled(false); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onException(Preference preference, CommandException exception) { | 
|  | if (exception.getCommandError() == CommandException.Error.FDN_CHECK_FAILURE) { | 
|  | onError(preference, FDN_CHECK_FAILURE); | 
|  | } else if (exception.getCommandError() == CommandException.Error.RADIO_NOT_AVAILABLE) { | 
|  | onError(preference, RADIO_OFF_ERROR); | 
|  | } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_DIAL) { | 
|  | onError(preference, STK_CC_SS_TO_DIAL_ERROR); | 
|  | } else if (exception.getCommandError() == CommandException.Error | 
|  | .SS_MODIFIED_TO_DIAL_VIDEO) { | 
|  | onError(preference, STK_CC_SS_TO_DIAL_VIDEO_ERROR); | 
|  | } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_USSD) { | 
|  | onError(preference, STK_CC_SS_TO_USSD_ERROR); | 
|  | } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_SS) { | 
|  | onError(preference, STK_CC_SS_TO_SS_ERROR); | 
|  | } else { | 
|  | preference.setEnabled(false); | 
|  | onError(preference, EXCEPTION_ERROR); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onCancel(DialogInterface dialog) { | 
|  | if (DBG) dumpState(); | 
|  | finish(); | 
|  | } | 
|  |  | 
|  | protected 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. | 
|  | } | 
|  | } | 
|  |  | 
|  | /* package */ void dumpState() { | 
|  | Log.d(LOG_TAG, "dumpState begin"); | 
|  | for (String key : mBusyList) { | 
|  | Log.d(LOG_TAG, "mBusyList: key=" + key); | 
|  | } | 
|  | Log.d(LOG_TAG, "dumpState end"); | 
|  | } | 
|  | } |