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