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