1 package com.android.phone;
2 
3 import com.android.internal.telephony.CallForwardInfo;
4 import com.android.internal.telephony.CommandException;
5 import com.android.internal.telephony.CommandsInterface;
6 import com.android.internal.telephony.Phone;
7 
8 import android.app.AlertDialog;
9 import android.content.Context;
10 import android.content.DialogInterface;
11 import android.content.res.TypedArray;
12 import android.os.AsyncResult;
13 import android.os.Handler;
14 import android.os.Message;
15 import android.text.TextUtils;
16 import android.util.AttributeSet;
17 import android.util.Log;
18 import android.view.View;
19 
20 import static com.android.phone.TimeConsumingPreferenceActivity.RESPONSE_ERROR;
21 import static com.android.phone.TimeConsumingPreferenceActivity.EXCEPTION_ERROR;
22 
23 public class CallForwardEditPreference extends EditPhoneNumberPreference {
24     private static final String LOG_TAG = "CallForwardEditPreference";
25     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
26 
27     private static final String SRC_TAGS[]       = {"{0}"};
28     private CharSequence mSummaryOnTemplate;
29     /**
30      * Remembers which button was clicked by a user. If no button is clicked yet, this should have
31      * {@link DialogInterface#BUTTON_NEGATIVE}, meaning "cancel".
32      *
33      * TODO: consider removing this variable and having getButtonClicked() in
34      * EditPhoneNumberPreference instead.
35      */
36     private int mButtonClicked;
37     private int mServiceClass;
38     private MyHandler mHandler = new MyHandler();
39     int reason;
40     private Phone mPhone;
41     CallForwardInfo callForwardInfo;
42     private TimeConsumingPreferenceListener mTcpListener;
43 
CallForwardEditPreference(Context context, AttributeSet attrs)44     public CallForwardEditPreference(Context context, AttributeSet attrs) {
45         super(context, attrs);
46 
47         mSummaryOnTemplate = this.getSummaryOn();
48 
49         TypedArray a = context.obtainStyledAttributes(attrs,
50                 R.styleable.CallForwardEditPreference, 0, R.style.EditPhoneNumberPreference);
51         mServiceClass = a.getInt(R.styleable.CallForwardEditPreference_serviceClass,
52                 CommandsInterface.SERVICE_CLASS_VOICE);
53         reason = a.getInt(R.styleable.CallForwardEditPreference_reason,
54                 CommandsInterface.CF_REASON_UNCONDITIONAL);
55         a.recycle();
56 
57         if (DBG) Log.d(LOG_TAG, "mServiceClass=" + mServiceClass + ", reason=" + reason);
58     }
59 
CallForwardEditPreference(Context context)60     public CallForwardEditPreference(Context context) {
61         this(context, null);
62     }
63 
init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone)64     void init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) {
65         mPhone = phone;
66         mTcpListener = listener;
67 
68         if (!skipReading) {
69             mPhone.getCallForwardingOption(reason,
70                     mHandler.obtainMessage(MyHandler.MESSAGE_GET_CF,
71                             // unused in this case
72                             CommandsInterface.CF_ACTION_DISABLE,
73                             MyHandler.MESSAGE_GET_CF, null));
74             if (mTcpListener != null) {
75                 mTcpListener.onStarted(this, true);
76             }
77         }
78     }
79 
80     @Override
onBindDialogView(View view)81     protected void onBindDialogView(View view) {
82         // default the button clicked to be the cancel button.
83         mButtonClicked = DialogInterface.BUTTON_NEGATIVE;
84         super.onBindDialogView(view);
85     }
86 
87     @Override
onClick(DialogInterface dialog, int which)88     public void onClick(DialogInterface dialog, int which) {
89         super.onClick(dialog, which);
90         mButtonClicked = which;
91     }
92 
93     @Override
onDialogClosed(boolean positiveResult)94     protected void onDialogClosed(boolean positiveResult) {
95         super.onDialogClosed(positiveResult);
96 
97         if (DBG) Log.d(LOG_TAG, "mButtonClicked=" + mButtonClicked
98                 + ", positiveResult=" + positiveResult);
99         // Ignore this event if the user clicked the cancel button, or if the dialog is dismissed
100         // without any button being pressed (back button press or click event outside the dialog).
101         if (this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
102             int action = (isToggled() || (mButtonClicked == DialogInterface.BUTTON_POSITIVE)) ?
103                     CommandsInterface.CF_ACTION_REGISTRATION :
104                     CommandsInterface.CF_ACTION_DISABLE;
105             int time = (reason != CommandsInterface.CF_REASON_NO_REPLY) ? 0 : 20;
106             final String number = getPhoneNumber();
107 
108             if (DBG) Log.d(LOG_TAG, "callForwardInfo=" + callForwardInfo);
109 
110             if (action == CommandsInterface.CF_ACTION_REGISTRATION
111                     && callForwardInfo != null
112                     && callForwardInfo.status == 1
113                     && number.equals(callForwardInfo.number)) {
114                 // no change, do nothing
115                 if (DBG) Log.d(LOG_TAG, "no change, do nothing");
116             } else {
117                 // set to network
118                 if (DBG) Log.d(LOG_TAG, "reason=" + reason + ", action=" + action
119                         + ", number=" + number);
120 
121                 // Display no forwarding number while we're waiting for
122                 // confirmation
123                 setSummaryOn("");
124 
125                 // the interface of Phone.setCallForwardingOption has error:
126                 // should be action, reason...
127                 mPhone.setCallForwardingOption(action,
128                         reason,
129                         number,
130                         time,
131                         mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
132                                 action,
133                                 MyHandler.MESSAGE_SET_CF));
134 
135                 if (mTcpListener != null) {
136                     mTcpListener.onStarted(this, false);
137                 }
138             }
139         }
140     }
141 
handleCallForwardResult(CallForwardInfo cf)142     void handleCallForwardResult(CallForwardInfo cf) {
143         callForwardInfo = cf;
144         if (DBG) Log.d(LOG_TAG, "handleGetCFResponse done, callForwardInfo=" + callForwardInfo);
145 
146         setToggled(callForwardInfo.status == 1);
147         setPhoneNumber(callForwardInfo.number);
148     }
149 
updateSummaryText()150     private void updateSummaryText() {
151         if (isToggled()) {
152             CharSequence summaryOn;
153             final String number = getRawPhoneNumber();
154             if (number != null && number.length() > 0) {
155                 String values[] = { number };
156                 summaryOn = TextUtils.replace(mSummaryOnTemplate, SRC_TAGS, values);
157             } else {
158                 summaryOn = getContext().getString(R.string.sum_cfu_enabled_no_number);
159             }
160             setSummaryOn(summaryOn);
161         }
162 
163     }
164 
165     // Message protocol:
166     // what: get vs. set
167     // arg1: action -- register vs. disable
168     // arg2: get vs. set for the preceding request
169     private class MyHandler extends Handler {
170         static final int MESSAGE_GET_CF = 0;
171         static final int MESSAGE_SET_CF = 1;
172 
173         @Override
handleMessage(Message msg)174         public void handleMessage(Message msg) {
175             switch (msg.what) {
176                 case MESSAGE_GET_CF:
177                     handleGetCFResponse(msg);
178                     break;
179                 case MESSAGE_SET_CF:
180                     handleSetCFResponse(msg);
181                     break;
182             }
183         }
184 
handleGetCFResponse(Message msg)185         private void handleGetCFResponse(Message msg) {
186             if (DBG) Log.d(LOG_TAG, "handleGetCFResponse: done");
187 
188             mTcpListener.onFinished(CallForwardEditPreference.this, msg.arg2 != MESSAGE_SET_CF);
189 
190             AsyncResult ar = (AsyncResult) msg.obj;
191 
192             callForwardInfo = null;
193             if (ar.exception != null) {
194                 if (DBG) Log.d(LOG_TAG, "handleGetCFResponse: ar.exception=" + ar.exception);
195                 if (ar.exception instanceof CommandException) {
196                     mTcpListener.onException(CallForwardEditPreference.this,
197                             (CommandException) ar.exception);
198                 } else {
199                     // Most likely an ImsException and we can't handle it the same way as
200                     // a CommandException. The best we can do is to handle the exception
201                     // the same way as mTcpListener.onException() does when it is not of type
202                     // FDN_CHECK_FAILURE.
203                     mTcpListener.onError(CallForwardEditPreference.this, EXCEPTION_ERROR);
204                 }
205             } else {
206                 if (ar.userObj instanceof Throwable) {
207                     mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
208                 }
209                 CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
210                 if (cfInfoArray.length == 0) {
211                     if (DBG) Log.d(LOG_TAG, "handleGetCFResponse: cfInfoArray.length==0");
212                     setEnabled(false);
213                     mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
214                 } else {
215                     for (int i = 0, length = cfInfoArray.length; i < length; i++) {
216                         if (DBG) Log.d(LOG_TAG, "handleGetCFResponse, cfInfoArray[" + i + "]="
217                                 + cfInfoArray[i]);
218                         if ((mServiceClass & cfInfoArray[i].serviceClass) != 0) {
219                             // corresponding class
220                             CallForwardInfo info = cfInfoArray[i];
221                             handleCallForwardResult(info);
222 
223                             // Show an alert if we got a success response but
224                             // with unexpected values.
225                             // Currently only handle the fail-to-disable case
226                             // since we haven't observed fail-to-enable.
227                             if (msg.arg2 == MESSAGE_SET_CF &&
228                                     msg.arg1 == CommandsInterface.CF_ACTION_DISABLE &&
229                                     info.status == 1) {
230                                 CharSequence s;
231                                 switch (reason) {
232                                     case CommandsInterface.CF_REASON_BUSY:
233                                         s = getContext().getText(R.string.disable_cfb_forbidden);
234                                         break;
235                                     case CommandsInterface.CF_REASON_NO_REPLY:
236                                         s = getContext().getText(R.string.disable_cfnry_forbidden);
237                                         break;
238                                     default: // not reachable
239                                         s = getContext().getText(R.string.disable_cfnrc_forbidden);
240                                 }
241                                 AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
242                                 builder.setNeutralButton(R.string.close_dialog, null);
243                                 builder.setTitle(getContext().getText(R.string.error_updating_title));
244                                 builder.setMessage(s);
245                                 builder.setCancelable(true);
246                                 builder.create().show();
247                             }
248                         }
249                     }
250                 }
251             }
252 
253             // Now whether or not we got a new number, reset our enabled
254             // summary text since it may have been replaced by an empty
255             // placeholder.
256             updateSummaryText();
257         }
258 
handleSetCFResponse(Message msg)259         private void handleSetCFResponse(Message msg) {
260             AsyncResult ar = (AsyncResult) msg.obj;
261 
262             if (ar.exception != null) {
263                 if (DBG) Log.d(LOG_TAG, "handleSetCFResponse: ar.exception=" + ar.exception);
264                 // setEnabled(false);
265             }
266             if (DBG) Log.d(LOG_TAG, "handleSetCFResponse: re get");
267             mPhone.getCallForwardingOption(reason,
268                     obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
269         }
270     }
271 }
272