1 package com.android.phone; 2 3 import com.android.internal.telephony.CommandException; 4 5 import android.app.AlertDialog; 6 import android.app.Dialog; 7 import android.app.ProgressDialog; 8 import android.content.DialogInterface; 9 import android.preference.Preference; 10 import android.preference.PreferenceActivity; 11 import android.util.Log; 12 import android.view.WindowManager; 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 = "TimeConsumingPreferenceActivity"; 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 57 private final ArrayList<String> mBusyList = new ArrayList<String>(); 58 59 protected boolean mIsForeground = false; 60 61 @Override onCreateDialog(int id)62 protected Dialog onCreateDialog(int id) { 63 if (id == BUSY_READING_DIALOG || id == BUSY_SAVING_DIALOG) { 64 ProgressDialog dialog = new ProgressDialog(this); 65 dialog.setTitle(getText(R.string.updating_title)); 66 dialog.setIndeterminate(true); 67 68 switch(id) { 69 case BUSY_READING_DIALOG: 70 dialog.setCancelable(true); 71 dialog.setOnCancelListener(this); 72 dialog.setMessage(getText(R.string.reading_settings)); 73 return dialog; 74 case BUSY_SAVING_DIALOG: 75 dialog.setCancelable(false); 76 dialog.setMessage(getText(R.string.updating_settings)); 77 return dialog; 78 } 79 return null; 80 } 81 82 if (id == RESPONSE_ERROR || id == RADIO_OFF_ERROR || id == EXCEPTION_ERROR 83 || id == FDN_CHECK_FAILURE || id == STK_CC_SS_TO_DIAL_ERROR 84 || id == STK_CC_SS_TO_USSD_ERROR || id == STK_CC_SS_TO_SS_ERROR) { 85 AlertDialog.Builder builder = new AlertDialog.Builder(this); 86 87 int msgId; 88 int titleId = R.string.error_updating_title; 89 90 switch (id) { 91 case RESPONSE_ERROR: 92 msgId = R.string.response_error; 93 builder.setPositiveButton(R.string.close_dialog, mDismiss); 94 break; 95 case RADIO_OFF_ERROR: 96 msgId = R.string.radio_off_error; 97 // The error is not recoverable on dialog exit. 98 builder.setPositiveButton(R.string.close_dialog, mDismissAndFinish); 99 break; 100 case FDN_CHECK_FAILURE: 101 msgId = R.string.fdn_check_failure; 102 builder.setPositiveButton(R.string.close_dialog, mDismiss); 103 break; 104 case STK_CC_SS_TO_DIAL_ERROR: 105 msgId = R.string.stk_cc_ss_to_dial_error; 106 builder.setPositiveButton(R.string.close_dialog, mDismiss); 107 break; 108 case STK_CC_SS_TO_USSD_ERROR: 109 msgId = R.string.stk_cc_ss_to_ussd_error; 110 builder.setPositiveButton(R.string.close_dialog, mDismiss); 111 break; 112 case STK_CC_SS_TO_SS_ERROR: 113 msgId = R.string.stk_cc_ss_to_ss_error; 114 builder.setPositiveButton(R.string.close_dialog, mDismiss); 115 break; 116 case EXCEPTION_ERROR: 117 default: 118 msgId = R.string.exception_error; 119 // The error is not recoverable on dialog exit. 120 builder.setPositiveButton(R.string.close_dialog, mDismiss); 121 break; 122 } 123 124 builder.setTitle(getText(titleId)); 125 builder.setMessage(getText(msgId)); 126 builder.setCancelable(false); 127 AlertDialog dialog = builder.create(); 128 129 // make the dialog more obvious by blurring the background. 130 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 131 132 return dialog; 133 } 134 return null; 135 } 136 137 @Override onResume()138 public void onResume() { 139 super.onResume(); 140 mIsForeground = true; 141 } 142 143 @Override onPause()144 public void onPause() { 145 super.onPause(); 146 mIsForeground = false; 147 } 148 149 @Override onStarted(Preference preference, boolean reading)150 public void onStarted(Preference preference, boolean reading) { 151 if (DBG) dumpState(); 152 if (DBG) Log.d(LOG_TAG, "onStarted, preference=" + preference.getKey() 153 + ", reading=" + reading); 154 mBusyList.add(preference.getKey()); 155 156 if (mIsForeground) { 157 if (reading) { 158 showDialog(BUSY_READING_DIALOG); 159 } else { 160 showDialog(BUSY_SAVING_DIALOG); 161 } 162 } 163 164 } 165 166 @Override onFinished(Preference preference, boolean reading)167 public void onFinished(Preference preference, boolean reading) { 168 if (DBG) dumpState(); 169 if (DBG) Log.d(LOG_TAG, "onFinished, preference=" + preference.getKey() 170 + ", reading=" + reading); 171 mBusyList.remove(preference.getKey()); 172 173 if (mBusyList.isEmpty()) { 174 if (reading) { 175 dismissDialogSafely(BUSY_READING_DIALOG); 176 } else { 177 dismissDialogSafely(BUSY_SAVING_DIALOG); 178 } 179 } 180 preference.setEnabled(true); 181 } 182 183 @Override onError(Preference preference, int error)184 public void onError(Preference preference, int error) { 185 if (DBG) dumpState(); 186 if (DBG) Log.d(LOG_TAG, "onError, preference=" + preference.getKey() + ", error=" + error); 187 188 if (mIsForeground) { 189 showDialog(error); 190 } 191 preference.setEnabled(false); 192 } 193 194 @Override onException(Preference preference, CommandException exception)195 public void onException(Preference preference, CommandException exception) { 196 if (exception.getCommandError() == CommandException.Error.FDN_CHECK_FAILURE) { 197 onError(preference, FDN_CHECK_FAILURE); 198 } else if (exception.getCommandError() == CommandException.Error.RADIO_NOT_AVAILABLE) { 199 onError(preference, RADIO_OFF_ERROR); 200 } else { 201 preference.setEnabled(false); 202 onError(preference, EXCEPTION_ERROR); 203 } 204 } 205 206 @Override onCancel(DialogInterface dialog)207 public void onCancel(DialogInterface dialog) { 208 if (DBG) dumpState(); 209 finish(); 210 } 211 dismissDialogSafely(int id)212 private void dismissDialogSafely(int id) { 213 try { 214 dismissDialog(id); 215 } catch (IllegalArgumentException e) { 216 // This is expected in the case where we were in the background 217 // at the time we would normally have shown the dialog, so we didn't 218 // show it. 219 } 220 } 221 dumpState()222 /* package */ void dumpState() { 223 Log.d(LOG_TAG, "dumpState begin"); 224 for (String key : mBusyList) { 225 Log.d(LOG_TAG, "mBusyList: key=" + key); 226 } 227 Log.d(LOG_TAG, "dumpState end"); 228 } 229 } 230