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