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