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 = FrameworksUtils.makeAlertDialogBuilder(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 
196         //If the error is due to RESPONSE_ERROR, do not disable the item so end user
197         //can continue to interact with it.
198         if (error != RESPONSE_ERROR) {
199             preference.setEnabled(false);
200         }
201     }
202 
203     @Override
onException(Preference preference, CommandException exception)204     public void onException(Preference preference, CommandException exception) {
205         Log.i(LOG_TAG, "onError, preference=" + preference.getKey() + ", exception=" + exception);
206         if (exception.getCommandError() == CommandException.Error.FDN_CHECK_FAILURE) {
207             onError(preference, FDN_CHECK_FAILURE);
208         } else if (exception.getCommandError() == CommandException.Error.RADIO_NOT_AVAILABLE) {
209             onError(preference, RADIO_OFF_ERROR);
210         } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_DIAL) {
211             onError(preference, STK_CC_SS_TO_DIAL_ERROR);
212         } else if (exception.getCommandError() == CommandException.Error
213                 .SS_MODIFIED_TO_DIAL_VIDEO) {
214             onError(preference, STK_CC_SS_TO_DIAL_VIDEO_ERROR);
215         } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_USSD) {
216             onError(preference, STK_CC_SS_TO_USSD_ERROR);
217         } else if (exception.getCommandError() == CommandException.Error.SS_MODIFIED_TO_SS) {
218             onError(preference, STK_CC_SS_TO_SS_ERROR);
219         } else if (exception.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED) {
220             preference.setEnabled(false);
221             // Don't show an error dialog; just disable it if the request is not supported.
222             Log.i(LOG_TAG, "onError, suppress error dialog as not supported");
223         } else {
224             preference.setEnabled(false);
225             onError(preference, EXCEPTION_ERROR);
226         }
227     }
228 
229     @Override
onCancel(DialogInterface dialog)230     public void onCancel(DialogInterface dialog) {
231         if (DBG) dumpState();
232         finish();
233     }
234 
dismissDialogSafely(int id)235     protected void dismissDialogSafely(int id) {
236         try {
237             dismissDialog(id);
238         } catch (IllegalArgumentException e) {
239             // This is expected in the case where we were in the background
240             // at the time we would normally have shown the dialog, so we didn't
241             // show it.
242         }
243     }
244 
dumpState()245     /* package */ void dumpState() {
246         Log.d(LOG_TAG, "dumpState begin");
247         for (String key : mBusyList) {
248             Log.d(LOG_TAG, "mBusyList: key=" + key);
249         }
250         Log.d(LOG_TAG, "dumpState end");
251     }
252 }
253