1 package com.android.phone;
2 
3 import static com.android.phone.TimeConsumingPreferenceActivity.EXCEPTION_ERROR;
4 import static com.android.phone.TimeConsumingPreferenceActivity.RESPONSE_ERROR;
5 
6 import android.app.AlertDialog;
7 import android.content.Context;
8 import android.content.DialogInterface;
9 import android.content.res.TypedArray;
10 import android.os.AsyncResult;
11 import android.os.Handler;
12 import android.os.Message;
13 import android.os.PersistableBundle;
14 import android.telephony.CarrierConfigManager;
15 import android.telephony.PhoneNumberUtils;
16 import android.telephony.TelephonyManager;
17 import android.text.BidiFormatter;
18 import android.text.SpannableString;
19 import android.text.TextDirectionHeuristics;
20 import android.text.TextUtils;
21 import android.util.AttributeSet;
22 import android.util.Log;
23 import android.view.View;
24 
25 import com.android.internal.telephony.CallForwardInfo;
26 import com.android.internal.telephony.CommandException;
27 import com.android.internal.telephony.CommandsInterface;
28 import com.android.internal.telephony.Phone;
29 import com.android.internal.telephony.flags.Flags;
30 
31 import java.util.HashMap;
32 import java.util.Locale;
33 
34 public class CallForwardEditPreference extends EditPhoneNumberPreference {
35     private static final String LOG_TAG = "CallForwardEditPreference";
36 
37     private static final String SRC_TAGS[]       = {"{0}"};
38 
39     private static final int DEFAULT_NO_REPLY_TIMER_FOR_CFNRY = 20;
40 
41     private CharSequence mSummaryOnTemplate;
42     /**
43      * Remembers which button was clicked by a user. If no button is clicked yet, this should have
44      * {@link DialogInterface#BUTTON_NEGATIVE}, meaning "cancel".
45      *
46      * TODO: consider removing this variable and having getButtonClicked() in
47      * EditPhoneNumberPreference instead.
48      */
49     private int mButtonClicked;
50     private int mServiceClass;
51     private MyHandler mHandler = new MyHandler();
52     int reason;
53     private Phone mPhone;
54     CallForwardInfo callForwardInfo;
55     private TimeConsumingPreferenceListener mTcpListener;
56     // Should we replace CF queries containing an invalid number with "Voicemail"
57     private boolean mReplaceInvalidCFNumber = false;
58     private boolean mCallForwardByUssd = false;
59     private CarrierXmlParser mCarrierXmlParser;
60     private int mPreviousCommand = MyHandler.MESSAGE_GET_CF;
61     private Object mCommandException;
62     private CarrierXmlParser.SsEntry.SSAction mSsAction =
63             CarrierXmlParser.SsEntry.SSAction.UNKNOWN;
64     private int mAction;
65     private HashMap<String, String> mCfInfo;
66     private long mDelayMillisAfterUssdSet = 1000;
67 
CallForwardEditPreference(Context context, AttributeSet attrs)68     public CallForwardEditPreference(Context context, AttributeSet attrs) {
69         super(context, attrs);
70 
71         mSummaryOnTemplate = this.getSummaryOn();
72 
73         TypedArray a = context.obtainStyledAttributes(attrs,
74                 R.styleable.CallForwardEditPreference, 0, R.style.EditPhoneNumberPreference);
75         mServiceClass = a.getInt(R.styleable.CallForwardEditPreference_serviceClass,
76                 CommandsInterface.SERVICE_CLASS_VOICE);
77         reason = a.getInt(R.styleable.CallForwardEditPreference_reason,
78                 CommandsInterface.CF_REASON_UNCONDITIONAL);
79         a.recycle();
80 
81         Log.d(LOG_TAG, "mServiceClass=" + mServiceClass + ", reason=" + reason);
82     }
83 
CallForwardEditPreference(Context context)84     public CallForwardEditPreference(Context context) {
85         this(context, null);
86     }
87 
init(TimeConsumingPreferenceListener listener, Phone phone, boolean replaceInvalidCFNumber, boolean callForwardByUssd)88     void init(TimeConsumingPreferenceListener listener, Phone phone,
89             boolean replaceInvalidCFNumber, boolean callForwardByUssd) {
90         mPhone = phone;
91         mTcpListener = listener;
92         mReplaceInvalidCFNumber = replaceInvalidCFNumber;
93         mCallForwardByUssd = callForwardByUssd;
94         Log.d(LOG_TAG,
95                 "init :mReplaceInvalidCFNumber " + mReplaceInvalidCFNumber + ", mCallForwardByUssd "
96                         + mCallForwardByUssd);
97         if (mCallForwardByUssd) {
98             mCfInfo = new HashMap<String, String>();
99             TelephonyManager telephonyManager = new TelephonyManager(getContext(),
100                     phone.getSubId());
101             mCarrierXmlParser = new CarrierXmlParser(getContext(),
102                     telephonyManager.getSimCarrierId());
103         }
104     }
105 
restoreCallForwardInfo(CallForwardInfo cf)106     void restoreCallForwardInfo(CallForwardInfo cf) {
107         handleCallForwardResult(cf);
108         updateSummaryText();
109     }
110 
111     @Override
onBindDialogView(View view)112     protected void onBindDialogView(View view) {
113         // default the button clicked to be the cancel button.
114         mButtonClicked = DialogInterface.BUTTON_NEGATIVE;
115         super.onBindDialogView(view);
116     }
117 
118     @Override
onClick(DialogInterface dialog, int which)119     public void onClick(DialogInterface dialog, int which) {
120         super.onClick(dialog, which);
121         mButtonClicked = which;
122     }
123 
124     @Override
onDialogClosed(boolean positiveResult)125     protected void onDialogClosed(boolean positiveResult) {
126         super.onDialogClosed(positiveResult);
127 
128         Log.d(LOG_TAG, "mButtonClicked=" + mButtonClicked + ", positiveResult=" + positiveResult);
129         // Ignore this event if the user clicked the cancel button, or if the dialog is dismissed
130         // without any button being pressed (back button press or click event outside the dialog).
131         if (isUnknownStatus() && this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
132             int action = (mButtonClicked == DialogInterface.BUTTON_POSITIVE) ?
133                 CommandsInterface.CF_ACTION_REGISTRATION :
134                 CommandsInterface.CF_ACTION_DISABLE;
135             final String number = (action == CommandsInterface.CF_ACTION_DISABLE) ?
136                     "" : getPhoneNumber();
137 
138             Log.d(LOG_TAG, "reason=" + reason + ", action=" + action + ", number=" + number);
139 
140             // Display no forwarding number while we're waiting for confirmation.
141             setSummaryOff("");
142 
143             mPhone.setCallForwardingOption(action,
144                     reason,
145                     number,
146                     mServiceClass,
147                     0,
148                     mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
149                         action,
150                         MyHandler.MESSAGE_SET_CF));
151         } else if (this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
152             int action = (isToggled() || (mButtonClicked == DialogInterface.BUTTON_POSITIVE)) ?
153                     CommandsInterface.CF_ACTION_REGISTRATION :
154                     CommandsInterface.CF_ACTION_DISABLE;
155             int time = 0;
156             if (reason == CommandsInterface.CF_REASON_NO_REPLY) {
157                 PersistableBundle carrierConfig = PhoneGlobals.getInstance()
158                         .getCarrierConfigForSubId(mPhone.getSubId());
159                 if (carrierConfig.getBoolean(
160                         CarrierConfigManager.KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true)) {
161                     if (Flags.setNoReplyTimerForCfnry()) {
162                         // Get timer value from carrier config
163                         time = carrierConfig.getInt(
164                                 CarrierConfigManager.KEY_NO_REPLY_TIMER_FOR_CFNRY_SEC_INT,
165                                 DEFAULT_NO_REPLY_TIMER_FOR_CFNRY);
166                     } else {
167                         time = DEFAULT_NO_REPLY_TIMER_FOR_CFNRY;
168                     }
169                 }
170             }
171             final String number = getPhoneNumber();
172 
173             Log.d(LOG_TAG, "callForwardInfo=" + callForwardInfo);
174 
175             if (action == CommandsInterface.CF_ACTION_REGISTRATION
176                     && callForwardInfo != null
177                     && callForwardInfo.status == 1
178                     && number.equals(callForwardInfo.number)) {
179                 // no change, do nothing
180                 Log.d(LOG_TAG, "no change, do nothing");
181             } else {
182                 // set to network
183                 Log.d(LOG_TAG, "reason=" + reason + ", action=" + action
184                         + ", number=" + number);
185 
186                 // Display no forwarding number while we're waiting for
187                 // confirmation
188                 setSummaryOn("");
189                 if (!mCallForwardByUssd) {
190                     // the interface of Phone.setCallForwardingOption has error:
191                     // should be action, reason...
192                     mPhone.setCallForwardingOption(action,
193                             reason,
194                             number,
195                             mServiceClass,
196                             time,
197                             mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
198                                     action,
199                                     MyHandler.MESSAGE_SET_CF));
200                 } else {
201                     if (action == CommandsInterface.CF_ACTION_REGISTRATION) {
202                         mCfInfo.put(CarrierXmlParser.TAG_ENTRY_NUMBER, number);
203                         mCfInfo.put(CarrierXmlParser.TAG_ENTRY_TIME, Integer.toString(time));
204                     } else {
205                         mCfInfo.clear();
206                     }
207                     mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_SET_CF_USSD,
208                             action, MyHandler.MESSAGE_SET_CF));
209                 }
210                 if (mTcpListener != null) {
211                     mTcpListener.onStarted(this, false);
212                 }
213             }
214         }
215     }
216 
handleCallForwardResult(CallForwardInfo cf)217     private void handleCallForwardResult(CallForwardInfo cf) {
218         callForwardInfo = cf;
219         Log.d(LOG_TAG, "handleGetCFResponse done, callForwardInfo=" + callForwardInfo);
220         // In some cases, the network can send call forwarding URIs for voicemail that violate the
221         // 3gpp spec. This can cause us to receive "numbers" that are sequences of letters. In this
222         // case, we must detect these series of characters and replace them with "Voicemail".
223         // PhoneNumberUtils#formatNumber returns null if the number is not valid.
224         if (mReplaceInvalidCFNumber && !TextUtils.isEmpty(callForwardInfo.number)
225                 && (PhoneNumberUtils.formatNumber(callForwardInfo.number, getCurrentCountryIso())
226                 == null)) {
227             callForwardInfo.number = getContext().getString(R.string.voicemail);
228             Log.i(LOG_TAG, "handleGetCFResponse: Overridding CF number");
229         }
230 
231         setUnknownStatus(callForwardInfo.status == CommandsInterface.SS_STATUS_UNKNOWN);
232         setToggled(callForwardInfo.status == 1);
233         boolean displayVoicemailNumber = false;
234         if (TextUtils.isEmpty(callForwardInfo.number)) {
235             PersistableBundle carrierConfig =
236                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
237             if (carrierConfig != null) {
238                 displayVoicemailNumber = carrierConfig.getBoolean(CarrierConfigManager
239                         .KEY_DISPLAY_VOICEMAIL_NUMBER_AS_DEFAULT_CALL_FORWARDING_NUMBER_BOOL);
240                 Log.d(LOG_TAG, "display voicemail number as default");
241             }
242         }
243         String voicemailNumber = mPhone.getVoiceMailNumber();
244         setPhoneNumber(displayVoicemailNumber ? voicemailNumber : callForwardInfo.number);
245     }
246 
247     /**
248      * Starts the Call Forwarding Option query to the network and calls
249      * {@link TimeConsumingPreferenceListener#onStarted}. Will call
250      * {@link TimeConsumingPreferenceListener#onFinished} when finished, or
251      * {@link TimeConsumingPreferenceListener#onError} if an error has occurred.
252      */
startCallForwardOptionsQuery()253     void startCallForwardOptionsQuery() {
254         if (!mCallForwardByUssd) {
255             mPhone.getCallForwardingOption(reason, mServiceClass,
256                     mHandler.obtainMessage(MyHandler.MESSAGE_GET_CF,
257                             // unused in this case
258                             CommandsInterface.CF_ACTION_DISABLE,
259                             MyHandler.MESSAGE_GET_CF, null));
260         } else {
261             mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
262                     // unused in this case
263                     CommandsInterface.CF_ACTION_DISABLE, MyHandler.MESSAGE_GET_CF, null));
264         }
265         if (mTcpListener != null) {
266             mTcpListener.onStarted(this, true);
267         }
268     }
269 
updateSummaryText()270     private void updateSummaryText() {
271         if (isToggled()) {
272             final String number = getRawPhoneNumber();
273             if (number != null && number.length() > 0) {
274                 // Wrap the number to preserve presentation in RTL languages.
275                 String wrappedNumber = BidiFormatter.getInstance().unicodeWrap(
276                         number, TextDirectionHeuristics.LTR);
277                 String values[] = { wrappedNumber };
278                 String summaryOn = String.valueOf(
279                         TextUtils.replace(mSummaryOnTemplate, SRC_TAGS, values));
280                 int start = summaryOn.indexOf(wrappedNumber);
281 
282                 SpannableString spannableSummaryOn = new SpannableString(summaryOn);
283                 PhoneNumberUtils.addTtsSpan(spannableSummaryOn,
284                         start, start + wrappedNumber.length());
285                 setSummaryOn(spannableSummaryOn);
286             } else {
287                 setSummaryOn(getContext().getString(R.string.sum_cfu_enabled_no_number));
288             }
289         }
290 
291     }
292 
293     /**
294      * @return The ISO 3166-1 two letters country code of the country the user is in based on the
295      *      network location.
296      */
getCurrentCountryIso()297     private String getCurrentCountryIso() {
298         final TelephonyManager telephonyManager =
299                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
300         if (telephonyManager == null) {
301             return "";
302         }
303         return telephonyManager.getNetworkCountryIso().toUpperCase(Locale.ROOT);
304     }
305 
306     // Message protocol:
307     // what: get vs. set
308     // arg1: action -- register vs. disable
309     // arg2: get vs. set for the preceding request
310     private class MyHandler extends Handler {
311         static final int MESSAGE_GET_CF = 0;
312         static final int MESSAGE_SET_CF = 1;
313         static final int MESSAGE_GET_CF_USSD = 2;
314         static final int MESSAGE_SET_CF_USSD = 3;
315 
316         TelephonyManager.UssdResponseCallback mUssdCallback =
317                 new TelephonyManager.UssdResponseCallback() {
318                     @Override
319                     public void onReceiveUssdResponse(final TelephonyManager telephonyManager,
320                             String request, CharSequence response) {
321                         if (mSsAction == CarrierXmlParser.SsEntry.SSAction.UNKNOWN) {
322                             return;
323                         }
324 
325                         HashMap<String, String> analysisResult = mCarrierXmlParser.getFeature(
326                                 CarrierXmlParser.FEATURE_CALL_FORWARDING)
327                                 .getResponseSet(mSsAction,
328                                         response.toString());
329 
330                         Throwable throwableException = null;
331                         if (analysisResult.get(CarrierXmlParser.TAG_RESPONSE_STATUS_ERROR)
332                                 != null) {
333                             throwableException = new CommandException(
334                                     CommandException.Error.GENERIC_FAILURE);
335                         }
336 
337                         Object obj = null;
338                         if (mSsAction == CarrierXmlParser.SsEntry.SSAction.QUERY) {
339                             obj = makeCallForwardInfo(analysisResult);
340                         }
341 
342                         sendCfMessage(obj, throwableException);
343                     }
344 
345                     @Override
346                     public void onReceiveUssdResponseFailed(final TelephonyManager telephonyManager,
347                             String request, int failureCode) {
348                         Log.d(LOG_TAG, "receive the ussd result failed");
349                         Throwable throwableException = new CommandException(
350                                 CommandException.Error.GENERIC_FAILURE);
351                         sendCfMessage(null, throwableException);
352                     }
353                 };
354 
355         @Override
handleMessage(Message msg)356         public void handleMessage(Message msg) {
357             switch (msg.what) {
358                 case MESSAGE_GET_CF:
359                     handleGetCFResponse(msg);
360                     break;
361                 case MESSAGE_SET_CF:
362                     handleSetCFResponse(msg);
363                     break;
364                 case MESSAGE_GET_CF_USSD:
365                     prepareUssdCommand(msg, CarrierXmlParser.SsEntry.SSAction.QUERY);
366                     break;
367                 case MESSAGE_SET_CF_USSD:
368                     prepareUssdCommand(msg, CarrierXmlParser.SsEntry.SSAction.UNKNOWN);
369                     break;
370             }
371         }
372 
handleGetCFResponse(Message msg)373         private void handleGetCFResponse(Message msg) {
374             Log.d(LOG_TAG, "handleGetCFResponse: done");
375 
376             mTcpListener.onFinished(CallForwardEditPreference.this, msg.arg2 != MESSAGE_SET_CF);
377 
378             AsyncResult ar = (AsyncResult) msg.obj;
379 
380             callForwardInfo = null;
381             boolean summaryOff = false;
382             if (ar.exception != null) {
383                 Log.d(LOG_TAG, "handleGetCFResponse: ar.exception=" + ar.exception);
384                 if (ar.exception instanceof CommandException) {
385                     mTcpListener.onException(CallForwardEditPreference.this,
386                             (CommandException) ar.exception);
387                 } else {
388                     // Most likely an ImsException and we can't handle it the same way as
389                     // a CommandException. The best we can do is to handle the exception
390                     // the same way as mTcpListener.onException() does when it is not of type
391                     // FDN_CHECK_FAILURE.
392                     mTcpListener.onError(CallForwardEditPreference.this, EXCEPTION_ERROR);
393                 }
394             } else {
395                 if (ar.userObj instanceof Throwable) {
396                     mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
397                 }
398                 CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
399                 if (cfInfoArray == null || cfInfoArray.length == 0) {
400                     Log.d(LOG_TAG, "handleGetCFResponse: cfInfoArray.length==0");
401                     if (!(ar.userObj instanceof Throwable)) {
402                         mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
403                     }
404                 } else {
405                     for (int i = 0, length = cfInfoArray.length; i < length; i++) {
406                         Log.d(LOG_TAG, "handleGetCFResponse, cfInfoArray[" + i + "]="
407                                 + cfInfoArray[i]);
408                         if ((mServiceClass & cfInfoArray[i].serviceClass) != 0) {
409                             // corresponding class
410                             CallForwardInfo info = cfInfoArray[i];
411                             handleCallForwardResult(info);
412 
413                             summaryOff = (info.status == CommandsInterface.SS_STATUS_UNKNOWN);
414 
415                             if (ar.userObj instanceof Throwable) {
416                                 Log.d(LOG_TAG, "Skipped duplicated error dialog");
417                                 continue;
418                             }
419 
420                             // Show an alert if we got a success response but
421                             // with unexpected values.
422                             // Handle the fail-to-disable case.
423                             if (msg.arg2 == MESSAGE_SET_CF &&
424                                     msg.arg1 == CommandsInterface.CF_ACTION_DISABLE &&
425                                     info.status == 1) {
426                                 // Skip showing error dialog since some operators return
427                                 // active status even if disable call forward succeeded.
428                                 // And they don't like the error dialog.
429                                 if (isSkipCFFailToDisableDialog()) {
430                                     Log.d(LOG_TAG, "Skipped Callforwarding fail-to-disable dialog");
431                                     continue;
432                                 }
433                                 CharSequence s;
434                                 switch (reason) {
435                                     case CommandsInterface.CF_REASON_BUSY:
436                                         s = getContext().getText(R.string.disable_cfb_forbidden);
437                                         break;
438                                     case CommandsInterface.CF_REASON_NO_REPLY:
439                                         s = getContext().getText(R.string.disable_cfnry_forbidden);
440                                         break;
441                                     default: // not reachable
442                                         s = getContext().getText(R.string.disable_cfnrc_forbidden);
443                                 }
444                                 AlertDialog.Builder builder =
445                                         FrameworksUtils.makeAlertDialogBuilder(getContext());
446                                 builder.setNeutralButton(R.string.close_dialog, null);
447                                 builder.setTitle(getContext()
448                                         .getText(R.string.error_updating_title));
449                                 builder.setMessage(s);
450                                 builder.setCancelable(true);
451                                 builder.create().show();
452                             } else if (msg.arg2 == MESSAGE_SET_CF &&
453                                     msg.arg1 == CommandsInterface.CF_ACTION_REGISTRATION &&
454                                     info.status == 0) {
455                                 // Handle the fail-to-enable case.
456                                 CharSequence s = getContext()
457                                     .getText(R.string.registration_cf_forbidden);
458                                 AlertDialog.Builder builder =
459                                         FrameworksUtils.makeAlertDialogBuilder(getContext());
460                                 builder.setNeutralButton(R.string.close_dialog, null);
461                                 builder.setTitle(getContext()
462                                         .getText(R.string.error_updating_title));
463                                 builder.setMessage(s);
464                                 builder.setCancelable(true);
465                                 builder.create().show();
466                             }
467                         }
468                     }
469                 }
470             }
471 
472             // Now whether or not we got a new number, reset our enabled
473             // summary text since it may have been replaced by an empty
474             // placeholder.
475             // for CDMA, doesn't display summary.
476             if (summaryOff) {
477                 setSummaryOff("");
478             } else {
479                 // Now whether or not we got a new number, reset our enabled
480                 // summary text since it may have been replaced by an empty
481                 // placeholder.
482                 updateSummaryText();
483             }
484         }
485 
handleSetCFResponse(Message msg)486         private void handleSetCFResponse(Message msg) {
487             AsyncResult ar = (AsyncResult) msg.obj;
488             if (ar.exception != null) {
489                 Log.d(LOG_TAG, "handleSetCFResponse: ar.exception=" + ar.exception);
490                 // setEnabled(false);
491             }
492 
493             if (ar.result != null) {
494                 int arr = (int)ar.result;
495                 if (arr == CommandsInterface.SS_STATUS_UNKNOWN) {
496                     Log.d(LOG_TAG, "handleSetCFResponse: no need to re get in CDMA");
497                     mTcpListener.onFinished(CallForwardEditPreference.this, false);
498                     return;
499                 }
500             }
501 
502             Log.d(LOG_TAG, "handleSetCFResponse: re get");
503             if (!mCallForwardByUssd) {
504                 mPhone.getCallForwardingOption(reason, mServiceClass,
505                         obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
506             } else {
507                 mHandler.sendMessageDelayed(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
508                         msg.arg1, MyHandler.MESSAGE_SET_CF, ar.exception),
509                         mDelayMillisAfterUssdSet);
510             }
511         }
512 
prepareUssdCommand(Message msg, CarrierXmlParser.SsEntry.SSAction inputSsAction)513         private void prepareUssdCommand(Message msg,
514                 CarrierXmlParser.SsEntry.SSAction inputSsAction) {
515             mAction = msg.arg1;
516             mPreviousCommand = msg.arg2;
517             mCommandException = msg.obj;
518             mSsAction = inputSsAction;
519 
520             if (mSsAction != CarrierXmlParser.SsEntry.SSAction.QUERY) {
521                 if (mAction == CommandsInterface.CF_ACTION_REGISTRATION) {
522                     mSsAction = CarrierXmlParser.SsEntry.SSAction.UPDATE_ACTIVATE;
523                 } else {
524                     mSsAction = CarrierXmlParser.SsEntry.SSAction.UPDATE_DEACTIVATE;
525                 }
526             }
527 
528             new Thread(new Runnable() {
529                 @Override
530                 public void run() {
531                     sendUssdCommand(mUssdCallback, mSsAction, mCfInfo.isEmpty() ? null : mCfInfo);
532                 }
533             }).start();
534         }
535 
sendUssdCommand(TelephonyManager.UssdResponseCallback inputCallback, CarrierXmlParser.SsEntry.SSAction inputAction, HashMap<String, String> inputCfInfo)536         private void sendUssdCommand(TelephonyManager.UssdResponseCallback inputCallback,
537                 CarrierXmlParser.SsEntry.SSAction inputAction,
538                 HashMap<String, String> inputCfInfo) {
539             String newUssdCommand = mCarrierXmlParser.getFeature(
540                     CarrierXmlParser.FEATURE_CALL_FORWARDING)
541                     .makeCommand(inputAction, inputCfInfo);
542             TelephonyManager telephonyManager =
543                     (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
544             telephonyManager.sendUssdRequest(newUssdCommand, inputCallback, mHandler);
545         }
546 
makeGetCfMessage(int inputMsgWhat, int inputMsgArg2, Object inputMsgObj)547         private Message makeGetCfMessage(int inputMsgWhat, int inputMsgArg2, Object inputMsgObj) {
548             return mHandler.obtainMessage(inputMsgWhat,
549                     mAction,
550                     inputMsgArg2,
551                     inputMsgObj);
552         }
553 
makeSetCfMessage(int inputMsgWhat, int inputMsgArg2)554         private Message makeSetCfMessage(int inputMsgWhat, int inputMsgArg2) {
555             return mHandler.obtainMessage(inputMsgWhat,
556                     mAction,
557                     inputMsgArg2);
558         }
559 
sendCfMessage(Object inputArObj, Throwable inputThrowableException)560         private void sendCfMessage(Object inputArObj, Throwable inputThrowableException) {
561             Message message;
562             if (mSsAction == CarrierXmlParser.SsEntry.SSAction.UNKNOWN) {
563                 return;
564             }
565             if (mSsAction == CarrierXmlParser.SsEntry.SSAction.QUERY) {
566                 message = makeGetCfMessage(MyHandler.MESSAGE_GET_CF, mPreviousCommand,
567                         mCommandException);
568             } else {
569                 message = makeSetCfMessage(MyHandler.MESSAGE_SET_CF, MyHandler.MESSAGE_SET_CF);
570             }
571             AsyncResult.forMessage(message, inputArObj, inputThrowableException);
572             message.sendToTarget();
573         }
574 
makeCallForwardInfo(HashMap<String, String> inputInfo)575         private CallForwardInfo[] makeCallForwardInfo(HashMap<String, String> inputInfo) {
576             int tmpStatus = 0;
577             String tmpNumberStr = "";
578             int tmpTime = 0;
579             if (inputInfo != null && inputInfo.size() != 0) {
580                 String tmpStatusStr = inputInfo.get(CarrierXmlParser.TAG_RESPONSE_STATUS);
581 
582                 String tmpTimeStr = inputInfo.get(CarrierXmlParser.TAG_RESPONSE_TIME);
583                 if (!TextUtils.isEmpty(tmpStatusStr)) {
584                     if (tmpStatusStr.equals(
585                             CarrierXmlParser.TAG_COMMAND_RESULT_DEFINITION_ACTIVATE)) {
586                         tmpStatus = 1;
587                     } else if (tmpStatusStr.equals(
588                             CarrierXmlParser.TAG_COMMAND_RESULT_DEFINITION_DEACTIVATE)
589                             || tmpStatusStr.equals(
590                             CarrierXmlParser.TAG_COMMAND_RESULT_DEFINITION_UNREGISTER)) {
591                         tmpStatus = 0;
592                     }
593                 }
594 
595                 tmpNumberStr = inputInfo.get(CarrierXmlParser.TAG_RESPONSE_NUMBER);
596                 if (!TextUtils.isEmpty(tmpTimeStr)) {
597                     tmpTime = Integer.valueOf(inputInfo.get(CarrierXmlParser.TAG_RESPONSE_TIME));
598                 }
599             }
600 
601             CallForwardInfo[] newCallForwardInfo = new CallForwardInfo[1];
602             newCallForwardInfo[0] = new CallForwardInfo();
603             newCallForwardInfo[0].status = tmpStatus;
604             newCallForwardInfo[0].reason = reason;
605             newCallForwardInfo[0].serviceClass = mServiceClass;
606             newCallForwardInfo[0].number = tmpNumberStr;
607             newCallForwardInfo[0].timeSeconds = tmpTime;
608             return newCallForwardInfo;
609         }
610     }
611 
612     /*
613      * Get the config of whether skip showing CF fail-to-disable dialog
614      * from carrier config manager.
615      *
616      * @return boolean value of the config
617      */
isSkipCFFailToDisableDialog()618     private boolean isSkipCFFailToDisableDialog() {
619         PersistableBundle carrierConfig =
620                 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
621         if (carrierConfig != null) {
622             return carrierConfig.getBoolean(
623                     CarrierConfigManager.KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL);
624         } else {
625             // by default we should not skip
626             return false;
627         }
628     }
629 }
630