1 package com.android.phone; 2 3 import android.app.AlertDialog; 4 import android.app.Dialog; 5 import android.app.ProgressDialog; 6 import android.content.DialogInterface; 7 import android.preference.Preference; 8 import android.preference.PreferenceActivity; 9 import android.util.Log; 10 import android.view.WindowManager; 11 12 import com.android.internal.telephony.CommandException; 13 14 import java.util.ArrayList; 15 16 interface TimeConsumingPreferenceListener { onStarted(Preference preference, boolean reading)17 public void onStarted(Preference preference, boolean reading); onFinished(Preference preference, boolean reading)18 public void onFinished(Preference preference, boolean reading); onError(Preference preference, int error)19 public void onError(Preference preference, int error); onException(Preference preference, CommandException exception)20 public void onException(Preference preference, CommandException exception); 21 } 22 23 public class TimeConsumingPreferenceActivity extends PreferenceActivity 24 implements TimeConsumingPreferenceListener, 25 DialogInterface.OnCancelListener { 26 private static final String LOG_TAG = "TimeConsumingPrefActivity"; 27 private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); 28 29 private class DismissOnClickListener implements DialogInterface.OnClickListener { 30 @Override onClick(DialogInterface dialog, int which)31 public void onClick(DialogInterface dialog, int which) { 32 dialog.dismiss(); 33 } 34 } 35 private class DismissAndFinishOnClickListener implements DialogInterface.OnClickListener { 36 @Override onClick(DialogInterface dialog, int which)37 public void onClick(DialogInterface dialog, int which) { 38 dialog.dismiss(); 39 finish(); 40 } 41 } 42 private final DialogInterface.OnClickListener mDismiss = new DismissOnClickListener(); 43 private final DialogInterface.OnClickListener mDismissAndFinish 44 = new DismissAndFinishOnClickListener(); 45 46 private static final int BUSY_READING_DIALOG = 100; 47 private static final int BUSY_SAVING_DIALOG = 200; 48 49 static final int EXCEPTION_ERROR = 300; 50 static final int RESPONSE_ERROR = 400; 51 static final int RADIO_OFF_ERROR = 500; 52 static final int FDN_CHECK_FAILURE = 600; 53 static final int STK_CC_SS_TO_DIAL_ERROR = 700; 54 static final int STK_CC_SS_TO_USSD_ERROR = 800; 55 static final int STK_CC_SS_TO_SS_ERROR = 900; 56 static final int STK_CC_SS_TO_DIAL_VIDEO_ERROR = 1000; 57 58 private final ArrayList<String> mBusyList = new ArrayList<String>(); 59 60 protected boolean mIsForeground = false; 61 62 @Override onCreateDialog(int id)63 protected Dialog onCreateDialog(int id) { 64 if (id == BUSY_READING_DIALOG || id == BUSY_SAVING_DIALOG) { 65 ProgressDialog dialog = new ProgressDialog(this); 66 dialog.setTitle(getText(R.string.updating_title)); 67 dialog.setIndeterminate(true); 68 69 switch(id) { 70 case BUSY_READING_DIALOG: 71 dialog.setCancelable(true); 72 dialog.setOnCancelListener(this); 73 dialog.setMessage(getText(R.string.reading_settings)); 74 return dialog; 75 case BUSY_SAVING_DIALOG: 76 dialog.setCancelable(false); 77 dialog.setMessage(getText(R.string.updating_settings)); 78 return dialog; 79 } 80 return null; 81 } 82 83 if (id == RESPONSE_ERROR || id == RADIO_OFF_ERROR || id == EXCEPTION_ERROR 84 || id == FDN_CHECK_FAILURE || id == STK_CC_SS_TO_DIAL_ERROR 85 || id == STK_CC_SS_TO_USSD_ERROR || id == STK_CC_SS_TO_SS_ERROR 86 || id == STK_CC_SS_TO_DIAL_VIDEO_ERROR) { 87 AlertDialog.Builder builder = new AlertDialog.Builder(this); 88 89 int msgId; 90 int titleId = R.string.error_updating_title; 91 92 switch (id) { 93 case RESPONSE_ERROR: 94 msgId = R.string.response_error; 95 builder.setPositiveButton(R.string.close_dialog, mDismiss); 96 break; 97 case RADIO_OFF_ERROR: 98 msgId = R.string.radio_off_error; 99 // The error is not recoverable on dialog exit. 100 builder.setPositiveButton(R.string.close_dialog, mDismissAndFinish); 101 break; 102 case FDN_CHECK_FAILURE: 103 msgId = R.string.fdn_check_failure; 104 builder.setPositiveButton(R.string.close_dialog, mDismiss); 105 break; 106 case STK_CC_SS_TO_DIAL_ERROR: 107 msgId = R.string.stk_cc_ss_to_dial_error; 108 builder.setPositiveButton(R.string.close_dialog, mDismiss); 109 break; 110 case STK_CC_SS_TO_USSD_ERROR: 111 msgId = R.string.stk_cc_ss_to_ussd_error; 112 builder.setPositiveButton(R.string.close_dialog, mDismiss); 113 break; 114 case STK_CC_SS_TO_SS_ERROR: 115 msgId = R.string.stk_cc_ss_to_ss_error; 116 builder.setPositiveButton(R.string.close_dialog, mDismiss); 117 break; 118 case STK_CC_SS_TO_DIAL_VIDEO_ERROR: 119 msgId = R.string.stk_cc_ss_to_dial_video_error; 120 builder.setPositiveButton(R.string.close_dialog, mDismiss); 121 break; 122 case EXCEPTION_ERROR: 123 default: 124 msgId = R.string.exception_error; 125 // The error is not recoverable on dialog exit. 126 builder.setPositiveButton(R.string.close_dialog, mDismiss); 127 break; 128 } 129 130 builder.setTitle(getText(titleId)); 131 builder.setMessage(getText(msgId)); 132 builder.setCancelable(false); 133 AlertDialog dialog = builder.create(); 134 135 // make the dialog more obvious by blurring the background. 136 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 137 138 return dialog; 139 } 140 return null; 141 } 142 143 @Override onResume()144 public void onResume() { 145 super.onResume(); 146 mIsForeground = true; 147 } 148 149 @Override onPause()150 public void onPause() { 151 super.onPause(); 152 mIsForeground = false; 153 } 154 155 @Override onStarted(Preference preference, boolean reading)156 public void onStarted(Preference preference, boolean reading) { 157 if (DBG) dumpState(); 158 Log.i(LOG_TAG, "onStarted, preference=" + preference.getKey() + ", reading=" + reading); 159 mBusyList.add(preference.getKey()); 160 161 if (mIsForeground) { 162 if (reading) { 163 showDialog(BUSY_READING_DIALOG); 164 } else { 165 showDialog(BUSY_SAVING_DIALOG); 166 } 167 } 168 169 } 170 171 @Override onFinished(Preference preference, boolean reading)172 public void onFinished(Preference preference, boolean reading) { 173 if (DBG) dumpState(); 174 Log.i(LOG_TAG, "onFinished, preference=" + preference.getKey() + ", reading=" + reading); 175 mBusyList.remove(preference.getKey()); 176 177 if (mBusyList.isEmpty()) { 178 if (reading) { 179 dismissDialogSafely(BUSY_READING_DIALOG); 180 } else { 181 dismissDialogSafely(BUSY_SAVING_DIALOG); 182 } 183 } 184 preference.setEnabled(true); 185 } 186 187 @Override onError(Preference preference, int error)188 public void onError(Preference preference, int error) { 189 if (DBG) dumpState(); 190 Log.i(LOG_TAG, "onError, preference=" + preference.getKey() + ", error=" + error); 191 192 if (mIsForeground) { 193 showDialog(error); 194 } 195 preference.setEnabled(false); 196 } 197 198 @Override onException(Preference preference, CommandException exception)199 public void onException(Preference preference, CommandException exception) { 200 if (exception.getCommandError() == CommandException.Error.FDN_CHECK_FAILURE) { 201 onError(preference, FDN_CHECK_FAILURE); 202 } else if (exception.getCommandError() == CommandException.Error.RADIO_NOT_AVAILABLE) { 203 onError(preference, RADIO_OFF_ERROR); 204 } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_DIAL) { 205 onError(preference, STK_CC_SS_TO_DIAL_ERROR); 206 } else if (exception.getCommandError() == CommandException.Error 207 .SS_MODIFIED_TO_DIAL_VIDEO) { 208 onError(preference, STK_CC_SS_TO_DIAL_VIDEO_ERROR); 209 } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_USSD) { 210 onError(preference, STK_CC_SS_TO_USSD_ERROR); 211 } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_SS) { 212 onError(preference, STK_CC_SS_TO_SS_ERROR); 213 } else { 214 preference.setEnabled(false); 215 onError(preference, EXCEPTION_ERROR); 216 } 217 } 218 219 @Override onCancel(DialogInterface dialog)220 public void onCancel(DialogInterface dialog) { 221 if (DBG) dumpState(); 222 finish(); 223 } 224 dismissDialogSafely(int id)225 protected void dismissDialogSafely(int id) { 226 try { 227 dismissDialog(id); 228 } catch (IllegalArgumentException e) { 229 // This is expected in the case where we were in the background 230 // at the time we would normally have shown the dialog, so we didn't 231 // show it. 232 } 233 } 234 dumpState()235 /* package */ void dumpState() { 236 Log.d(LOG_TAG, "dumpState begin"); 237 for (String key : mBusyList) { 238 Log.d(LOG_TAG, "mBusyList: key=" + key); 239 } 240 Log.d(LOG_TAG, "dumpState end"); 241 } 242 } 243